I've used this a couple of times, and I was wondering if someone else had run across it as well...
Sometimes I've found it necessary to build an object that implements several interfaces, but whose clients will only use one of those interfaces at a time.
What happens is that when I pass the object as a parameter to a method whose argument is typed to an interface, that the interface "masks off" some of the methods in the (larger) protocol of the object passed in.
This is analogous to using bitmasks to test for a particular condition, where a single integer might represent multiple values since each bitmask only tests one bit.
Are you saying that you explicitly define separate interfaces in order to divide the API of a class into multiple logical units? If so, why do you need to do this? What is the context of this pattern? How does it differ from the use of interfaces to define AbstractInteractions?
Or are you saying that you often end up implementing multiple interfaces, and this has the effect of dividing the API of your class into multiple logical units? If so, then this is the normal result of using interfaces. I find it very rare to have an object implement a single interface, except for inner classes used as event adapters. I find these inner adapter classes are usually used for one of two reasons:
I'm reading this as being a more general type of something I see usually as the Mutable/Immutable split (e.g. ImmutableInterface)... (I may be wrong :-)
e.g.
//Immutable base interface ImmutablePoint? { int getX( ); int getY( ); } //Mutable Version interface Point extends ImmutablePoint? { void setX(int x); void setY(int y); }What usually happens is I have a point interface with all four methods, reallise I need an Immutable version some places and refactor (ExtractBaseClass?) to produce a version that "masks" the setters.
Or am I completely misunderstanding, Kyle ?
So is this a refactoring pattern that leads to the use of multiple AbstractInteractions?
Interesting point. I'm doing this sort of thing right now as a part of refactoring. We have a 3 tier application in Java in which the middle tier's external interface is tied to the particular GUI panels of the client tier. We're putting in a coarser business level of abstraction in which one object implements several of these GUI panel interfaces. This is a temporary measure to allow us to change the architecture of the middle tier and not change the client tier. Later we will change the client and get rid of all the extra panel based interfaces. But for the time being, when the client is handed the remote object all but the particular interface it asked for is masked out. --GregVaughn
To follow up, I just found a pleasant surprise in Java that simplifies this job. In my case above, some of the Interfaces have the same static final int member with different values. I was concerned about a class implementing a pair of these interfaces, but I'm happy to report that it works as expected. Here's a code example:
interface A { public static final int foo = 1; } interface B { public static final int foo = 2; } class Hmmm implements A, B { } public class Testing { public static void main(String[] args) { A a = new Hmmm(); System.out.println(a.foo); B b = (B)a; System.out.println(b.foo); //System.out.println(Hmmm.foo); //this line won't compile! :-) } }Output is:
1 2--GregVaughn
I believe the Mutable/Immutable split is a specific case of the general kind of thing that I'm referring to. I think Greg's example is closer to what I've done. I've always felt vaguely uneasy when I do it, but I've found the technique to be quite useful, especially when you are in the middle of development and you really intend to do more refactoring later.
This sounds just like RobertMartin's InterfaceSegregationPrinciple. It's a way to have a class whose implementation is cohesive but whose interface is not. You segregate the interface into separate abstract interfaces that the clients rely on and then implement all of them in the same class. If a client needs an interface that it uses to change then only it and the implementing class have to change, recompile, or relink. The other clients are left alone. -- PhilGoodwin
Kyle, can you flesh out the pattern with a context and forces? How does this pattern differ from AbstractInteractions? --NatPryce
More examples can be seen on the RolePattern page.