Интерфейсы, объявляющие методы с тезисами в качестве параметров - PullRequest
0 голосов
/ 20 мая 2009

У меня есть вопрос о передовой практике в следующих примерах:

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 всегда получал MyRequest, а YourService получал только YourRequest, а не наоборот? Очевидный ответ "if-instance-of-check" в MyService.process(...) кажется некрасивым и каким-то образом противоречащим принципам SOLID. Может быть, есть способы лучше?

Может быть, дженерики были бы хорошим решением? (Но как их использовать в коде, который должен работать под Java 1.4?)

Ответы [ 5 ]

6 голосов
/ 20 мая 2009

Проще говоря, вы создаете интерфейс, которого потом не хотите придерживаться, поэтому это не совсем идеальный дизайн.

Я имею в виду, что если MyService реализует Сервис, он должен иметь возможность принимать любые запросы. В противном случае он не следует заданному контракту.

Я хотел бы спросить, почему у вас вообще есть интерфейс Service в этом случае, и если он вам нужен (для других методов), подходит ли для него метод процесса (Request request), если подклассы не собираются почитай это.

3 голосов
/ 20 мая 2009

Если дизайн контракта заключается в том, что каждая служба может обрабатывать любой тип запроса, то ваша реализация 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>

edit: очевидно, что это не работает в 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 голосов
/ 20 мая 2009

На мой взгляд, дженерики подойдут здесь лучше. Ваши интерфейсы делают вид, что сервис может обрабатывать любые типы запросов. Но на самом деле реализации каждого из них кажутся тесно связанными.

0 голосов
/ 20 мая 2009

попробуйте ввести другой уровень косвенности:

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(); }
}
0 голосов
/ 20 мая 2009

Все, что реализует Сервис, должно ожидать реализации своих методов такими, какие они есть. Если MyService и YourService требуют разных прототипов методов, то это разные интерфейсы.

Подумайте об этом с другой стороны. Не зная реализацию за интерфейсом службы, любой вызывающий должен иметь возможность вызвать Service.process (запрос) с любой реализацией запроса и ожидать получения действительного ответа.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...