About a third of my code is wrapped inside a Facade class. Note that this isn’t a “God” class, but actually represents a single thing (called a Line
). Naturally, it delegates responsibilities to the subsystem behind it.
What ends up happening is that two of the subsystem classes (Output
and Timeline
) have all of their methods duplicated in the Line
class, which effectively makes Line
both an Output
and a Timeline
. It seems to make sense to make Output
and Timeline
interfaces, so that the Line
class can implement them both. At the same time, I’m worried about creating parallel class and interface structures.
You see, there are different types of lines AudioLine
, VideoLine
, which all use the same type of Timeline
, but different types of Output
(AudioOutput
and VideoOutput
, respectively). So that would mean that I’d have to create an AudioOutputInterface
and VideoOutputInterface
as well. So not only would I have to have parallel class hierarchy, but there would be a parallel interface hierarchy as well.
Is there any solution to this design flaw?
Here’s an image of the basic structure (minus the Timeline class, though know that each Line has-a Timeline):
NOTE: I just realized that the word ‘line’ in Timeline
might make is sound like is does a similar function as the Line
class. They don’t, just to clarify.
0
What ends up happening is that two of the subsystem classes (Output
and Timeline) have all of their methods duplicated in the Line class,
which effectively makes Line both an Output and a Timeline.
The above sentence sounds like bad design.
I would expect that most of the methods in a facade class invoke at multiple subsystem classes or at least multiple methods in a single subsystem class.
If you facade is doing lots of simple delegation (example, facade method doSomething
simply calls another class’ doSomething
), you probably should refactor.
Specifically, if a delegate class does not interact with the rest of the subsystem, the client should probably should probably interact with the delegate directly, instead of through the facade.
2
Are some of your clients interested chiefly in Line as a Timeline, and others interested in it chiefly as an Output? If so, consider sprouting classes or interfaces from Line that stand between it and clients, each of these new classes wraps a pointer to a Line and abstracts away implementation while focusing the API.
At first, the feels like a facade for a facade, but it opens up new refactoring horizons. You can pull methods from Line to the new classes. You may discover new helper classes you can extract. Perhaps one of your implementation classes will turn out to belong here as well.
I really agree with both of the other answers. The primary problem here is that Line
has multiple responsibilities. You are falling into the fallacy of believing that classes correspond to a “thing”, when really a class should correspond to a “responsibility”.
That being said, it is certainly possible for a class to have the single responsibility of “providing a single facade delegating to several other classes to simplify client code”. It sounds like that might be what you are describing; it depends whether Line
has any behavior of it’s own, besides delegation. I don’t usually do this, because I don’t find it cumbersome to have client code talk to several objects, but that may be chalked up to personal preference.
It seems to make sense to make Output and Timeline interfaces, so that
the Line class can implement them both. At the same time, I’m worried
about creating parallel class and interface structures.
What motivates you to do that? Is there some need for that change, or is it just that you think it would be “more right”? If the latter, I would just leave your code as is. Working code is king.