Premise: In my project I have two generically typed interfaces defining Request and Response respectively. A request is processed to yield a response, hence every response is built based on a request. A Processor interface processes a request to build the corresponding response.
Code: The request and response interfaces are:
interface Request<T1>
and
interface Response<T2>
respectively, where T2
and T1
represent generic request and response types (I am deliberately calling them by different names for clarity).
Now, since T2 is a Request, and T1 is a response, so the above code evolves to:
interface Request<T1 extends Response>
and
interface Response<T2 extends Request>
Note that: Request and Response interfaces do not share any inheritance relationship - what the above code only intends to communicate is: Request is typed with only some other type which is-a Response.
Now, consider the Request interface: since Response is again typed, and the response built out of a request will be tied to the original request type, hence, the above code evolves to:
interface Request<T1 extends Response<? extends Request<T1>>>
and
interface Response<T2 extends Request<? extends Response<T2>>
Now, the Processor interface is defined as:
interface Processor<R1 extends Request<R2>, R2 extends Response<R1>> {
R2 process(R1 request);
}
Concrete classes:
Request implementation:
class ConcreteRequest implements Request<ConcreteResponse> {
ConcreteResponse response;
...`
}
Response implementation:
class ConcreteResponse implements Response<ConcreteRequest> {
ConcreteRequest request;
...
}
Processor implementation:
class ConcreteProcessor implements Processor<ConcreteRequest, ConcreteResponse> {
ConcreteResponse process(ConcreteRequest request) {
...
}
}
Question: Is the above code over-designed? Is there a simplified way to represent a tuple of complementary input-output objects?
I think you don't need to link the
Request
and theResponse
in the type definition. They are tied by theProcessor
. Isn't something likesufficient ? Actually I'm not sure you need generic at all.
There is one use case where it's useful to have a generified Request/Response (or well, at least the Request). If the request is generified to contain the response type, the following call is "typesafe"
Now users of that method will see "typesafe" request-response calling. I'm calling that only "typesafe" because the implementation of that method probably has to cast the responses to T, so ClassCastExceptions are theoretically possible, but in most cases they would be considered as application logic errors.
I would not put the actual fields of Request/Response inside other, just use the generic typeinformation for "typesafe" request-response calling.
Unless I've totally misunderstood your question, you don't - and shouldn't - use generic for this kind of problem. Using polymorphism and/or composition will be much more appropriate. For example, if you need to integrate a copy of the request in the response (hardly necessary but thinkable) then you can add a reference to a request object in your response class.
Technically, this reference to a
Request
object could be defined using a type; however, you shouldn't do that because it will always be aRequest
object (either a base class or a derived subclass) and not some kind of arbitrary class that could change with each instanciation of a response.You use generic when the type of each referenced object is totally different (for example, a
List <String>
or aList<Request>
: there is no subclassing relationship between aString
and aRequest
object) or when the use of polymorphism will not be sufficient because you are defining one or more new virtual functions in a subclass that are not present in the superclass.Building a
Response
to be based on aRequest
because aRequest
is processed to yield aResponse
is definitely not the way to go and your currentProcessor
interface is a testimony to that.