Java接口扩展了问题
我必须实现一个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
因为在尝试添加详细信息之前,此服务还将validation该书是否实际存在。
这是可能的还是完全关闭我的设计理念,这实际上是一个糟糕的设计理念,好像其他接口改变了一样? 我是否会更好地为FrontEndServer
内的所有方法编写方法签名?
如果扩展接口(如果实现接口,则同样适用),则不能覆盖方法并使其抛出比原始方法更多的已检查exception。 你可以扔掉相同或更少,但不能更多。
想一想:
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
。 但不确定这是一个好方法。
扩展这两种接口的单一类型有什么用? 当客户依赖于两个不同的对象时,你会失去什么吗?
过度使用inheritance是一个常见的初学者错误,因为“inheritance”是面向对象编程的显着特征之一。 但是,在大多数情况下,成分是更好的选择。 在这种情况下,为什么不提供两个单独的服务? 然后,稍后添加CafeteriaService
和DormitoryService
不会影响任何现有接口。
关于设计, addBookToStudent
方法将受益于能够抛出BookNotFoundException
。 接口是脆弱的,在某种意义上,改变它们会破坏很多代码。 你必须在他们的初始设计中非常小心。 例如, BookNotFoundException
可能具体; 难道不存在会阻止向学生“添加”一本书的各种例外吗? (我猜测学生正在从借阅库中检查书籍。)例如: CheckOutLimitExceededException
, UnpaidFinePendingException
, AdultLiteraturePermissionException
等。
在设计接口时,请仔细考虑可能适合抽象级别的已检查exception类型,因为它们以后很难更改。
给你一些想法:
-
在接口中声明addBookToStudent方法以抛出BookNotFoundException。 尽管StudentServer可能永远不会实际抛出exception,但这并不意味着您无法将其置于界面中。
-
您可以创建一个新的exception – ObjectNotFoundException,并从那里inheritanceBookNotFoundException和StudentNotFoundException,然后声明addBookToStudent以抛出ObjectNotFoundException。
-
我可能会在“现实生活”中做些什么 – 让StudentServer与BookServer交谈以validation书籍ID并抛出exception本身,而不是在FrontEndServer中进行检查。 特别是如果StudentServer实际上直接由FrontEndServer以外的任何东西使用。
我建议您尝试将公开的API与用于实现function的API分开。 我的猜测是,RMI服务前端的目的是为调用应用程序提供分离和稳定性。
有了这个,我建议你:
- 编写要公开的API
- 编写在API和后端服务之间架起桥梁的实现
理论上,BookNotFoundException可以扩展RemoteExcepiton。
但是,我假设您无法控制StudentServer接口。 看来该接口的意图是不抛出BookNotFoundException。 虽然我可以理解你想要的原因,但界面似乎并不鼓励这样做。
方法而不是接口或类抛出exception。 因此,如果BookServer
接口中有一个方法,当您将其添加到接口时,它可能会引发exception。
如果您正在考虑在FrontEndServer
接口中向addBookToStudent
方法添加exception,那么答案就是不可能。 类和接口中的重写方法可能只会缩小exception或将其完全删除,但不会添加新的exception。
如果你仔细想想,你会发现这是合乎逻辑的。 您的FrontEndServer
可以通过某些代码用作BookServer。 编译期间的代码需要BookServer中定义的exception。 然后在运行时突然发生BookServer抛出exception,而BookServer接口中未定义exception。 如果该段代码只知道BookException是意外的,则没有catches或throws语句来处理它。