Java接口继承问题

3

我需要实现一个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中所有方法的签名吗?
6个回答

16
如果您扩展接口(同样适用于实现接口),则不能覆盖方法并使其抛出比原始方法更多的已检查异常。您可以抛出相同或更少的异常,但不能抛出更多的异常。
深思熟虑一下:
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可以扩展RuntimeExceptionRemoteException。不过,我不确定这是否是一个好的方法。


谢谢 - 看起来我只需在前端服务器中实现这些方法 - 不过公平地说,这样做似乎是有道理的。 - Malachi
虽然如果你想将“未找到书籍”异常定义为RuntimeException的一种类型,那么你可以在不声明它的情况下抛出它。但那是邪恶的。 - Guss

5
一个同时扩展这两个接口的单一类型有什么好处?当客户端依赖于两个不同的对象时,是否会失去任何东西?
过度使用继承是初学者常犯的错误之一,因为“继承”是面向对象编程的显著特征之一。然而,在大多数情况下,组合是更好的选择。在这种情况下,为什么不有两个单独的服务呢?那么,稍后添加CafeteriaService和DormitoryService不会影响任何现有接口。
关于设计,addBookToStudent方法可以受益于能够抛出BookNotFoundException。接口是脆弱的,因为以任何方式改变它们都会破坏大量代码。在初始设计中必须非常小心。例如,BookNotFoundException可能太具体了;难道不能存在各种异常来防止向学生“添加”书籍吗?例如:CheckOutLimitExceededException,UnpaidFinePendingException,AdultLiteraturePermissionException等。
在设计接口时,请仔细考虑适合抛出的已检查异常类型,因为稍后更改它们很困难。

2

以下是一些想法:

  1. 在接口中声明addBookToStudent方法抛出BookNotFoundException。即使StudentServer可能永远不会真正引发异常,也可以将其放入接口中。

  2. 您可以创建一个新的异常-ObjectNotFoundException,并让BookNotFoundException和StudentNotFoundException从中继承,然后声明addBookToStudent抛出ObjectNotFoundException。

  3. 在“现实生活”中,我可能会让StudentServer与BookServer通信以验证图书ID并自行引发异常,而不是在FrontEndServer中进行检查。特别是如果StudentServer除了FrontEndServer之外还会被其他任何东西直接使用。


2
我建议您将公开的API与用于实现功能的API分离。我猜测RMI服务的前端目的是提供调用应用程序的分离和稳定性。
因此,我建议您:
- 编写要公开的API - 编写实现,以桥接您的API和后端服务

1

如果BookNotFoundException扩展了RemoteExcepiton,理论上是可能的。

然而,我假设您无法控制StudentServer接口。该接口的意图似乎不是抛出BookNotFoundException异常。虽然我可以理解您想要这样做的原因,但该接口似乎并不鼓励这样做。


1

方法引发异常,而不是接口或类。因此,如果在BookServer接口中有一个方法,当您将其添加到接口时,它可能会向您抛出异常。

如果您想将异常添加到FrontEndServer接口中的addBookToStudent方法中,则答案是否定的,这是不可能的。在类和接口中重写的方法只能缩小异常或完全删除异常,但不能添加新异常。

思考一下,您会发现这是合乎逻辑的。您的FrontEndServer可能被某些代码用作BookServer。编译过程中的代码期望在BookServer中定义的异常。然后,在运行时突然由BookServer引发一个未在BookServer接口中定义的异常。如果那段代码只知道BookException是意外的,那么就没有捕获或抛出语句来处理它。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接