Goran said:
I'd say what you want goes against interface segregation principle of
SOLID (
http://butunclebob.com/ArticleS.UncleBob.PrinciplesOfOod). I
mean, if you're making interfaces, and even if you need two+
interfaces on one object in a given piece of code, there's nothing
wrong in passing two interface references in, or "dynamic_casting"
from one to another. What you seem to want to do is to separate your
interfaces (for e.g. clarity of design), but also mix them back again
(for e.g. convenience^^^). Sure, you can do it, but it's kinda sour..
Hmm. Following the very first link from the page you referenced, to
http://www.objectmentor.com/resources/articles/srp.pdf, we can see the
author suggests "fine-grained" interfaces and uses the modem as an
example (converted interfaces to C++):
class DataChannel {
public:
virtual void send(char) = 0;
virtual char recv() = 0;
virtual ~DataChannel() {}
};
class Connection {
public:
virtual void dial(const std::string &) = 0;
virtual void hangup() = 0;
virtual ~Connection() {}
};
Then, he introduces the concrete class (not an interface)
class Modem: public DataChannel, public Connection {
public:
void send(char);
char recv();
void dial(const std::string &);
void hangup();
~Modem();
};
as a necessary evil ("this is not desirable but maybe necessary").
As every OOD tutorial, seems perfectly logical until the real life
intervenes:
At some point, a couple of months or years down the road, it may very
well become desirable to segregate between sinks and source channels
(for example, to support simplex data connections or provide a base
class for a device that can't send in principle, like a keyboard or
cannot receive in principle like a printer):
class DataSink {
virtual void send(char) = 0;
~DataSink() {}
};
class DataSource {
virtual char recv() = 0;
~DataSource() {}
};
So, where does it leave DataChannel? Are we to change only one class,
DataChannel interface, and live with "sour" composite interface:
class DataChannel : public DataSink, public DataSource {
};
or all existing derived classes created in these 2 months or years, in
our and other organizations, for the sake of SOLIDity?
The lessons:
1. General: Take all principles with grain of salt (a rude analogy of
never say never)
2. Specific: the granularity of an OO-model inevitably gets finer as we
learn more about the domain area and need to satisfy more requirements.
It is impractical to get a complete model in the first release. Even if
we get it, it will become incomplete after the first round of the new
requirements (if our app is success, that is. If it is dead-born and
have no users, it may keep enjoying its OO-purity). As soon as we admit
the granularity will be getting finer as a result of *later changes*, we
thereby admit we may have to live with composite interfaces. Thus, there
is no reason to shy composite interfaces to start with -- instead we
should concentrate on less restrictive policies allowing us to maintain
composite interfaces in sustainable manner.
Just my 2c
Pavel
..