我必须实现一个RMI服务器,它将成为另外两个RMI服务的前端.因此,我认为合乎逻辑的做法是将此实现的接口用于其他两个服务的接口.
public interface FrontEndServer extends Remote, BookServer, StudentServer { // Block empty so far }
但是StudentServer上有一个方法
/** * Allows a student to borrow a book * * @param studentID of the student who wishes to borrow a book * @param bookID of the book the student wishes to borrow * @throws RemoteException * @throws StudentNotFoundException when a student is not found in the system */ void addBookToStudent(int studentID, int bookID) throws RemoteException, StudentNotFoundException;
我想FrontEndServer
也要抛出一个,BookNotFoundException
因为这个服务也将在尝试添加细节之前验证该书是否实际存在.
这是可能的还是完全关闭我的设计理念,这实际上是一个糟糕的设计理念,好像其他接口改变了一样?我会更好地为所有方法编写方法签名FrontEndServer
吗?
如果扩展接口(如果实现接口,则同样适用),则不能覆盖方法并使其抛出比原始方法更多的已检查异常.你可以扔掉相同或更少,但不能更多.
想一想:
interface A { void foo(); } interface B extends A { void foo() throws IOException; } A a = new B() { ... } a.foo();
可能会抛出IOException,但你无法知道.这就是为什么你不能这样做的原因.
这当然是完全可以接受的:
interface A { void foo() throws IOException; } interface B extends A { void foo(); } A a = new B() { ... } try { a.foo(); } catch (IOException e) { // must catch even though B.foo() won't throw one }
BookNotFoundException
然而,你可以扩展RuntimeException
或RemoteException
.但不确定这是一个好方法.
扩展这两种接口的单一类型有什么用?当客户依赖于两个不同的对象时,你会失去什么吗?
过度使用继承是一个常见的初学者错误,因为"继承"是面向对象编程的显着特征之一.但是,在大多数情况下,成分是更好的选择.在这种情况下,为什么不提供两个单独的服务?然后,添加CafeteriaService
并DormitoryService
稍后不会影响任何现有接口.
关于设计,该addBookToStudent
方法将受益于能够投掷BookNotFoundException
.接口是脆弱的,在某种意义上,改变它们会破坏很多代码.你必须在他们的初始设计中非常小心.例如,BookNotFoundException
可能是具体的; 难道不存在各种例外情况会妨碍向学生"添加"一本书吗?(我猜的学生检查出的书籍,借阅图书馆的.)例如为:CheckOutLimitExceededException
,UnpaidFinePendingException
,AdultLiteraturePermissionException
,等.
在设计接口时,请仔细考虑可能适合抽象级别的已检查异常类型,因为它们以后很难更改.