接口使用摘要作为参数声明方法

时间:2009-05-20 11:46:20

标签: java interface

我对以下示例中的最佳做法提出了这个问题:

interface Request;
interface Service {
  void process(Request request)
}

class MyService implements Service;
class YourService implements Service;

class MyRequest implements Request;
class YourRequest implements Request;

但是,如何确保MyService始终收到MyRequestYourService只会获得YourRequest,而不是相反的方式? MyService.process(...)中明显的答案“if-instance-of-check”看起来很丑陋并且不知何故反对SOLID原则。也许有更好的方法?

也许泛型会很好解决? (但是,如何在必须在Java 1.4下运行的代码中使用它们?)

5 个答案:

答案 0 :(得分:6)

简而言之,您正在建立一个您不想遵守的界面,因此它并不是一个理想的设计。

我的意思是,如果MyService实现了Service,那么它必须能够接受任何类型的请求。否则,它不遵循定义的合同。

我会质疑为什么你在这个实例中完全拥有Service接口,如果你确实需要它(对于其他方法)是否适合于那里的进程(请求请求)方法,如果子类不会尊重它。

答案 1 :(得分:3)

如果合同的设计是每个服务可以处理任何类型的请求,那么您的MyService实现(仅接受MyRequest(如果传入其他类型的请求则中断)是错误的。

如果合同的设计是Service和Request子类彼此映射,例如,MyService可以(并且应该)处理MyRequest,那么您将需要更改Service的接口。否则,问题中写入的当前界面不会执行问题描述的操作。一种解决方法是参数化服务接口:

interface Service<R> {
   void process(R request);
}

然后你的具体MyService将是

public class MyService implements Service<MyRequest> {
   public void process (MyRequest r) {/*blah*/}
}

你可以在JDK中看到这个实例的一个例子 - Comparator接口正是这样做的,原因完全相同。 http://java.sun.com/javase/6/docs/api/java/util/Comparator.html

我无法理解您的原因,但如果您仍想将MyRequest的层次限制为请求,那么您可以将Service<R>Service<R extends Request>交换

编辑:这显然不会在1.4中运行,所以为了做同样的事情[1],你需要使用访问者模式。它的丑陋,但1.4很难看=)

interface Service {
   void process(Request visitor);
}
interface RequestVisitor {
   void visitMyRequest(MyService service);
   void visitYourRequest(YourService service);
   void visitTheOtherRequest(TheOtherService  service);
}
interface Request extends RequestVisitor { /* and any extra methods required for request*/ }
public class MyService implements Service {
   public process(Request r) {r.visitMyRequest(this);}
   public void doSpecialMyProcessing(MyRequest request) { /* your code using MyRequest*/ }
}
public class YourService implements Service {
   public process(Request r) {r.visitYourRequest(this);}
   public void doSpecialYourProcessing(YourRequest request) { /* your code using YourRequest */ }
}
public class MyRequest implements Request {
   void visitMyRequest(MyService service) {
      service.doSpecialMyProcessing(this);
   }
   void visitYourRequest(YourService service) {
      throw new UnsupportedOperation("Cannot call visitYourRequest in MyRequest!");
   }
   void visitTheOtherRequest(TheOtherService  service) {
      throw new UnsupportedOperation("Cannot call visitTheOtherRequest in MyRequest!");
   }
}
public class YourRequest implements Request {
   void visitMyRequest(MyService service) {
      throw new UnsupportedOperation("Cannot call visitMyRequest in YourRequest !");
   }
   void visitYourRequest(YourService service) {
      service. doSpecialYourProcessing(this);
   }
   void visitTheOtherRequest(TheOtherService  service) {
      throw new UnsupportedOperation("Cannot call visitTheOtherRequest in YourRequest !");
   }
}

[1] 实际上它不一样,因为现在你需要为每个请求子类型编写一个方法。在1.4中,你必须强制转换和执行instanceof等,以实现1.5对泛型的处理。

答案 2 :(得分:2)

在我看来,仿制药在这里会更合适。您的接口假装服务可以处理任何类型的请求。但实际上每个的实现似乎是紧密耦合的。

答案 3 :(得分:0)

任何实现Service的东西都应该按原样实现它的方法。如果MyService和YourService需要不同的方法原型,那么它们就是不同的接口。

从另一个方向考虑它。在不知道Service接口背后的实现的情况下,任何调用者都应该能够使用Request的任何实现来调用Service.process(request),并期望得到有效的响应。

答案 4 :(得分:0)

尝试引入另一个间接层:

interface Module {
   Service createService();
   Request createRequest();
}

class MyModule implements Module {
   Service createService() { return new MyService(); } 
   Request createRequest() { return new MyRequest(); }
}

class YourModule implements Module {
   Service createService() { return new YourService(); } 
   Request createRequest() { return new YourRequest(); }
}