Generics with Bound Parameters (no wildcards)
- Is my inference correct as in ICommand definition?
No. Two reasons- You have written a small 'o' while passing it to
Mediator
. (I guess it's just a typing mistake.) - You passed
IObserver<T>
in stead ofO
toISubject
which would definitely cause a parameter bound mismatch.
- You have written a small 'o' while passing it to
Correct Version:
interface ICommand<T, M extends IMediator<T, S, O>, S extends ISubject<T, O>, O extends IObserver<T>>
- How to interpret the above case studies?
- The first thing you'd need to understand that you have one unknown type T and five interfaces.
- Therefore you would have total six concrete types which have to be included progressively in the interface declarations. (You explicitly asked not to bother about rationale of the design.)
- If you write them in a correct order, it becomes much more manageable.
Interface declarations:
interface IObserver<T>
interface ISubject<T, O extends IObserver<T>>
interface IMediator<T, O extends IObserver<T>, S extends ISubject<T,O>>
interface ICommand<T, O extends IObserver<T>, S extends ISubject<T, O>,
M extends IMediator<T, O, S>>
interface IProducerConsumer<T, O extends IObserver<T>, S extends ISubject<T, O>,
M extends IMediator<T, O, S>, C extends ICommand<T, O, S, M>>
- What are the best defintions assuming that I want to insert T and must able to get and put?
- If you want to get and put object of type T, what you probably need is bunch of interfaces which take only one parameter T. Generics will enforce that all would be compatible as T will be replaced by same type everywhere.
- Your current system is too rigid. In real scenario, you would never have so many implementations of these interfaces (unless you are re-implementing facebook in java) so that you'd have many possible combinations of the implementations and you want to ensure compatibility.
- Generics enforces type-safety by applying restrictions which are good. But you should not put restrictions just because you can put them. You are losing flexibility, readability and maintainability of your code.
- You should add bounds only when you need them. They should not affect the design in any way before contracts between interfaces have been decided.
Possibly sufficient way:
interface IObserver<T>
interface ISubject<T>
interface IMediator<T>
interface ICommand<T>
interface IProducerConsumer<T>
- What is the rules and relations of the type parameter definitions in interface and implemented classes?
- The only relation between type parameters in interfaces and implementing class that I can think of is that implementing class has to provide a type to replace the generic type parameter.
- In some cases, that type can again be a generic type in which case the responsibility of providing concrete type is forwarded to the code using the class reference or another class which extends that class. It may even be recursive!
- The rules are not written in the language, in stead, you are applying all the rules on this mechanism when you make any type parameter bound. So as long as you are supplying a type which qualifies against all of your rules, you are good to go.
- More rules means more robust but less flexible/readable. So do the trade of wisely.
Two simple cases:
// General way
private class ProductObserver implements IObserver<Product> { }
private ProductObserver productObserver;
// Aspect oriented way
private class LoggerObserver<T> implements IObserver<T> { }
private LoggerObserver<Product> loggerObserver;
- Lastly, I'd suggest you to read (comprehensive) Java Generics FAQ by Angelika Langer if you have any further doubt.
- If you keep experimenting like this, you might as well end up inventing a design pattern. Don't forget to share it with us when you do :D
Hope this helps.
Good luck.