Không có cách nào để yêu cầu triển khai ném ngoại lệ qua giao diện, ngay cả trong các ngôn ngữ như Java nơi bạn có thể tuyên bố rằng một phương thức có thể ném ngoại lệ.
Có thể có một cách để đảm bảo (ở một mức độ nào đó nhưng không hoàn toàn) rằng một ngoại lệ được ném ra. Bạn có thể tạo một triển khai trừu tượng của giao diện của bạn. Sau đó, bạn có thể triển khai GetUser
phương thức là cuối cùng trong lớp trừu tượng và sử dụng mẫu chiến lược để gọi một thành viên khác, được bảo vệ của lớp con và ném một ngoại lệ nếu nó trả về bất cứ thứ gì ngoài người dùng hợp lệ (như null). Điều này vẫn có thể rơi xuống nếu, giả sử, nhà phát triển khác trả về một loại đối tượng null User
, nhưng họ thực sự sẽ phải làm việc để lật đổ ý định ở đây. Họ cũng có thể chỉ thực hiện lại giao diện của bạn, cũng rất tệ, vì vậy bạn có thể xem xét thay thế hoàn toàn giao diện bằng lớp trừu tượng.
(Kết quả tương tự có thể đạt được bằng cách sử dụng ủy quyền thay vì phân lớp với thứ gì đó giống như trang trí gói.)
Một tùy chọn khác có thể là tạo ra một bộ kiểm tra sự phù hợp mà tất cả các mã thực hiện phải vượt qua để được đưa vào. Hiệu quả của việc này phụ thuộc vào mức độ kiểm soát của bạn đối với liên kết của mã khác với mã của bạn.
Tôi cũng đồng ý với những người khác rằng tài liệu rõ ràng và thông tin liên lạc được đưa ra khi một yêu cầu như thế này được mong đợi nhưng không thể được thực thi hoàn toàn trong mã.
Mã ví dụ:
Phương pháp phân lớp:
public abstract class ExceptionalUserRepository : IUserRepository
{
public sealed User GetUser(int user_id)
{
User u = FindUserByID(user_id);
if(u == null)
{
throw new UserNotFoundException();
}
return u;
}
// subclasses implement this method instead
protected abstract User FindUserByID(int user_id);
// More code here
}
Phương pháp trang trí:
public sealed class DecoratedUserRepository : IUserRepository
{
private readonly IUserRepository _userRepository;
public DecoratedUserRepository(IUserRepository userRepository)
{
_userRepository = userRepository;
}
public User GetUser(int user_id)
{
User u = _userRepository.GetUser(user_id);
if(u == null)
{
throw new UserNotFoundException();
}
return u;
}
// More code here
}
public class SomeClass
{
private readonly IUserRepository _userRepository;
// They now *have* to pass in exactly what you want
public SomeClass(DecoratedUserRepository userRepository)
{
_userRepository = userRepository;
}
// More code
}
Một điểm nhanh cuối cùng tôi muốn làm cho tôi quên trước đó là bằng cách thực hiện bất kỳ điều nào trong số này, bạn đang buộc mình phải thực hiện cụ thể hơn, có nghĩa là các nhà phát triển triển khai có được sự tự do ít hơn nhiều.