Reputation: 367
I'm using ObjectAid with Eclipse to generate UML class diagrams for my latest Java project, and I currently have a handful of situations like this, where I have a dependency between two interfaces, as well as one of the implementations of one of the interfaces. Here, foo
is the graphics library I'm using.
In the previous example, FooCanvas
draws ITexture
objects to the screen, and both FooCanvas
and its interface, ICanvas
, take ITexture
objects as arguments to their methods.
The method in the canvas classes which cause this dependency is the following:
void drawTexture(ITexture texture, float x, float y);
Additionally, I tried a variation on the method signature using Java's generics:
<T extends ITexture> void drawTexture(T texture, float x, float y);
The result of this was a class diagram where the only dependencies where between the interfaces and the implementing classes, and no dependency by a canvas object on a texture. I'm not sure if this is more ideal or not.
Is the dependency of both the interface and implementation on another interface an expected pattern, or is it typical and/or possible to keep the implementation 'isolated' from its interfaces dependencies? Or is the generic method the ideal solution?
Upvotes: 3
Views: 391
Reputation: 2278
Your problem is that you are trying to address the wrong problem. One of the major points of Object oriented design is robustness and flexibility in terms of how much you can change certain implementation without changing/breaking other code.
You are trying to ask if a certain pattern is ideal or not? But the problem is: what is "Ideal" ? I'll will quote from Scot Meyers article How Non-Member Functions Improve Encapsulation: When it comes to encapsulation, sometimes less is more. This article is about C++, but the concepts he was trying to conduct applies regardless of the language.
Encapsulation is a means, not an end. There's nothing inherently desirable about encapsulation. Encapsulation is useful only because it yields other things in our software that we care about. In particular, it yields flexibility and robustness.
The question that you should be asking is:
how much code might be broken is to count the functions that might be affected. That is, if changing one implementation leads to more potentially broken functions than does changing another implementation.
Regarding your example it is not particularly easy for someone else to tell you what is ideal. Should you expose ITexture
interface? should you introduce a new interface called IDrawable
that the Texture extends ? The current approach is ok. But I don't actually know, because I don't know the implementation! maybe everything will break if you changed the texture implementation! **This is a question only you are able to answer while taking into account the points I mentioned above:
Upvotes: 3