The real smell in the pattern as depicted in your link and most books is that Component
has the methods of a Composite
. I think this is probably because the pattern is fairly old and has been repeated that way for years. My take is that only the Composite
should have any methods related to compositing.
I once converted a board game over to a computer game. The playing pieces were placed on a map of earth, divided up into hexagons. 99% of all hexagons represented a single location. Unfortunately, a few of the hexagons contained multiple locations, for example, some had a couple islands inside them. I used the composite pattern to represent these locations, but not as depicted on your link. It was something like this (in Java):
public interface Location {
Set<Army> getArmies();
}
public class SingleLocation implements Location {
public Set<Army> getArmies() {
return armies ;
}
private Set<Army> armies = new HashSet<Army>();
}
public class CompositeLocation implements Location {
public Set<Army> getArmies() {
Set<Army> armies = new HashSet<Army>();
for(Location subLocation: subLocations) {
armies.addAll(subLocation.getArmies());
}
return armies;
}
public void addSubLocation(Location location) {
subLocations.add(location);
}
private Set<Location> subLocations = new HashSet<Location>();
}
Note that only the Composite
has compositing methods, and doesn't even expose the fact that it has children to most clients (in this example, the client only wants a list of Armies from a location - the fact that they are at many sub-locations is irrelevant).
Keep in mind design patterns are not set-in-stone things you must implement exactly. Think of them as recipes. When you follow a recipe while cooking, you certainly can just follow it exactly. However, some cooks will throw in their own twists on the recipe. Others won't even look at it because they are experts and can throw something together in the spirit of the recipe without even thinking about it. The same goes for design patterns. They are malleable recipes.
You can also take those SOLID principles too far. If you read Robert Martin's articles, he states that applying the principles across the board without any thought will yield overly complex code. Software is designed through a series of trade-offs and balancings - sometimes you forgo pure SOLID because it yields cleaner less complex code. If you were to make your code perfectly encapsulated, flexible, decoupled, etc., you will have invented a new programming language :-)