If the design of the contract is that each Service can process any kind of Request, then your implementation of MyService , which only takes MyRequest (and breaks if other kinds of Requests are passed in), is wrong.
If the design of the contract is that Service and Request subclasses maps to each other, e.g., MyService can (and should) only process a MyRequest, then you will need to change the interface of Service. Otherwise, the current interface as written in the question does not do what the question describes it to do. One way to fix is to parameterize the Service interface:
interface Service<R> {
void process(R request);
}
then your concrete MyService will be
public class MyService implements Service<MyRequest> {
public void process (MyRequest r) {/*blah*/}
}
You can see an example of this in action in the JDK - the Comparator interface does exactly this, for exactly the same reason. http://java.sun.com/javase/6/docs/api/java/util/Comparator.html
I cant see why you would, but if you still want to restrict the hierachy of MyRequest to be a request, then you can swap Service<R>
with Service<R extends Request>
edit: this obviously doesnt run in 1.4, so to do the same thing[1] , you will need to use a visitor pattern. Its uglier, but 1.4 is ugly =)
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] actually its not the same, because now you will need to write a method for each request subtype. In 1.4, you would have to cast and do instanceof etc, to achieve what 1.5 can do with generics.