On Sep 2, 5:38 am, Pavel
<pauldontspamt...@removeyourself.dontspam.yahoo> wrote:
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").
Frankly, I don't see why the author put in "not desirable" part. It's
all about the coherence of any given part of the code. Code that deals
with data exchange it oblivious to "connection" aspect. Conversely,
code that deals with connectivity aspect is oblivious to data exchange
aspect. (Or at least, they are/could be in the example). But a modem
is a beast that unifies the two. So what? That does not change the
abstract "data exchange" setup, nor "connectivity" setup. There is in
fact nothing "undesirable".
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.
I __think__ I understand your meaning, and if so, I agree with
you :-). The hard cold truth is that __change__ is a bitch. In a
situation you describe, going from DataChanel to DataSink/Source pair
seems very reasonable. But the thing is, calling code will change,
too. Code that deals with keyboard (and other data sources) has no
business even knowing "sinks".
to Sink and Source at the first place). That is, it has to be more like
written anew, not really channged.
So the change is the external force that influences the design.
There's IMO absolutely no way around that.
Yes, this seems to be our common point. My take out of it is that if one
Goran.