Responding to _dee...
Actually, Facade is an appropriate analogy, with the requirement that
the facade be accessible in the same way as the sub-objects (hence the
use of interfaces). Now that I think of it, that's probably why Nick
mentioned multiple inheritance--it does look a bit like that.
In most cases each sub-object will implement 90% to 100% of the
interfaces' requirements. There are odd things that don't fit (like
my pixel dimensions for an audio file analogy) but not enough to
warrant a complete change in superstructure.
Yes, that does sound like Facade. If I understand this, one object, say
Group1, provides 90% of what the client wants but some other object, say
Group2, provides the other 10%. However, you want that allocation to be
transparent to the client. That is, you want the client to use I1 for
100% of the desired functionality.
But in that case one has different interfaces:
class master : I1
{
// provides all responsibilities to client in one interface
// dispatches to Group1 or Group2, as needed
}
class Group1 : I2
{
// provides 90% of the I1 responsibilities
}
class Group2 : I3
{
// provides 10% of the I1 responsibilities
}
If so, then I don't see any way around a somewhat tedious dispatch in
Master because that sort of re-dispatching is what Facade does.
However, if the split is really 90/10, then I would consider daisy
chaining Group1 and Group2. That is, let Group1 re-dispatch the 10% to
Group2 transparently to the client. Then Group1 provides the full
interface and the client only talks to Group1. (In effect this makes
Group1 the Facade but we are putting 90% of the functionality there as
well and letting it dispatch only 10% to Group2.)
The price of that, though, is much tighter coupling of Group1 and
Group2. If there is a change to Group2, then Group1 will very likely
also have to change. That may or may not be a problem depending on how
likely things are to change and whether the Group1/Group2 is a simple
message re-dispatch or is a more complicated collaboration.
[Note the the GoF pattern implementations all use this sort of
re-dispatch when they provide delegation rather than letting the client
talk directly to the delegated object. Aesthetically that is not good
OOA/D practice but the nature of the re-dispatch is so benign that it
rarely makes a difference.]
Those odd functions can be stubbed out with no real change in
high-level function. They'll just do nothing. The 'null object' that
implements those stubs would usually be the only other sub-object
required. I didn't want to restrict it to that though.
Now this is a very different problem. However, I have to ask: if they
do nothing, why have them at all? If this is really the case, then you
don't need Master or Group2 above at all. Group1 can provide the I1
interface to the client and just no-op the 10% of responsibilities that
aren't relevant.
That's too obvious, so I have to assume something else is going on.
Such as there is some context where the 10% is relevant and you will
need a dispatch. However, you can get around that problem in the model
above by adding a variation on the Observer pattern. The receiver is
either a null object or Group2. You register the appropriate one for
the context and Master dispatches as usual. Observer just makes sure
the right object get the message. (Obviously you can do the same thing
with the daisy-chain approach as well.)
There's some confusing overlap in the terms 'Adapter' and 'Facade' but
I didn't think Facade was confined to syntactical mismatches.
I'm just describing how Facade is /usually/ used. So long as you have
multiple objects (Group1, Group2, ...) that implement the functionality,
Facade is more appropriate. Adapter just resolves syntactic mismatches
with a single object's interface.
Sorry, you lost me. The interfaces that I had in mind don't need to
talk to each other. They spec the way that the user can regard the
final object: The user should be able to say "Give me the audio
specs" or "give me video specs". The object has the option to say
"That's not currently relevant."
OK. I inferred a different problem from the description.
I assume the use of 'option' here means that sometimes you need the
functionality and sometimes you don't. If so, I think a single object
that always provides the 90% combined with Observer, as described above,
would be the way to go.
That's exactly what I wanted it to look like to the client. But I
don't want to pass multiple Interfaces back to the client. I wanted
to collect them into one object. Other than that, it kind of sounds
like you're describing the same thing.
I think it is less about multiple interfaces than multiple relationships
and collaborations. If the functionality is spread across multiple
objects, then the client needs to collaborate with them on a
peer-to-peer basis. The fact that different interfaces are required for
those collaborations is incidental.
There are times, though, when one wants to hide multiple objects from
the client via Facade, but that is usually because those objects need to
collaborate with each other to service the client's request and one
wants to make that collaboration transparent to the client.
One can argue, though, that using Observer to deal with the 10% context
switching is a similar situation that one wants to make transparent to
the client. That is, the context switch is not relevant to what the
client /thinks/ it wants to do.
*************
There is nothing wrong with me that could
not be cured by a capful of Drano.
H. S. Lahman
(e-mail address removed)
Pathfinder Solutions -- Put MDA to Work
http://www.pathfindermda.com
blog:
http://pathfinderpeople.blogs.com/hslahman
Pathfinder is hiring:
http://www.pathfindermda.com/about_us/careers_pos3.php.
(888)OOA-PATH