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