I would probably consider it a code smell or even an anti-pattern to have a class that implements 23 interfaces. If it is indeed an anti-pattern, what would you call it? Or is it simply just not following the Single responsibility principle?
|
|
Royal Family: They don't do anything particularly crazy but they have a billion titles and are related to most other royals somehow. |
|||||||
|
|
I submit that this anti-pattern be named Jack of All Trades, or perhaps Too Many Hats. |
|||||||||||||||||||
|
|
The God Object comes to mind; a single object that knows how to do EVERYTHING. This comes from low adherence to the "cohesion" requirements of the two major design methodologies; if you have an object with 23 interfaces, you have an object that knows how to be 23 different things to its users, and those 23 different things are likely not along the lines of a single task or area of the system. In SOLID, while the creator of this object has obviously tried to follow the Interface Segregation Principle, they have violated a prior rule; Single Responsibility Principle. There's a reason it's "SOLID"; S always comes first when thinking about design, and all the other rules follow. In GRASP, the creator of such a class has neglected the "High Cohesion" rule; GRASP, unlike SOLID, teaches that an object doesn't HAVE to have a single responsibility, but at most it should have two or three very closely related responsibilities. |
|||||||||||||||
|
|
If I had to give it a name, I think I'd call it the Hydra:
Of particular relevance is the fact that it not only has many heads, but keeps growing more and more of them and is impossible to kill because of it. That's been my experience with these kinds of designs; developers just keep jamming more and more interfaces into it until it has too many to fit on the screen, and by then it's become so deeply entrenched in the program's design and assumptions that splitting it up is a hopeless prospect (if you try, you actually often end up needing more interfaces to bridge the gap). One early sign of impending doom due to a "Hydra" is frequent casting of one interface to another, without much sanity checking, and often to a target that makes no sense, as in:
It's obvious when taken out of context that there's something fishy about this code, but the likelihood of this happening goes up with the more "heads" an object grows, because developers intuitively know that they're always dealing with the same creature. Good luck ever doing any maintenance on an object that implements 23 interfaces. The chances of you not causing collateral damage in the process are slim to none. |
|||||||||
|
|
23 is Just a number! In most likely scenario, it is high enough to alarm. However, if we ask, what is the highest number of methods/interfaces before it can get a tag to be called as an "anti-pattern"? Is it 5 or 10 or 25? You realize that number is really not an answer because if 10 is good, 11 can also be - and then any integer after that. The real question is about complexity. And we should point out that lengthy code, number of methods or large size of the class by any measures is actually NOT the definition of complexity. Yes, a larger and bigger the code (larger number of methods) does make it difficult to read and grasp for a new beginner. It also handles potentially varied functionality, large number of exceptions, and quite evolved algorithms for various scenarios. This doesn't mean it is complex - it is only difficult to digest. On the other hand, relatively small size code which one can hope to read out in a few hours in and out- can still be complex. Here is when I think the code is (unnecessarily) complex. Every piece of wisdom of Object-oriented design can be put in here to define "complex" but I would restrict here to show when "so many methods" is an indication of complexity.
Probably there are many such situations you would see in a very evolved code and I am sure that many people can add scenarios, where "so many methods" just doesn't make sense or doesn't do what you would obviously think. This is the anti-pattern. My personal experience is that when projects that starts reasonably bottom up, many things for which there should have been genuine classes on their own -remains buried or worse still remains split between different classes and coupling increases. Most often what would have deserved 10 classes, but has only 4, it is likely that many of them have multi-purpose confusing and large number of methods. Call it a GOD and DRAGON, this is what is BAD. BUT you do come across VERY LARGE classes which are neatly consistent, they do have 30 methods - and are still very CLEAN. They can be good. |
||||
|
|
Classes should have exactly the right number of interfaces; no more, no less. Saying "too many" would be impossible without looking at whether or not all of those interfaces serve a useful purpose in that class. Declaring that an object implements an interface means that you have to implement its methods if you expect the class to compile. (I presume the class you're looking at does.) If everything in the interface is implemented and those implementations do something relative to the innards of the class, it would be hard to say that implementation shouldn't be there. The only case I can think of where an interface meeting those criteria wouldn't belong there is external: when nobody uses it. Some languages allow interfaces to be "subclassed" using a mechanism like Java's |
|||||||
|
|
Its sounds as thought they have a "getter"/"setter" pair for each property, as is normal for a typical "bean" and promoted all these methods to the interface. So how about calling it a "has bean". Or the more Rabelaisian "Flatulence" after the well known affects of too many beans. |
|||
|
|
The number of interfaces often grows when a generic object is used in different environments. In C# the variants of IComparable, IEqualityComparer and IComparer allow sorting in distinct setups, so you might end up implementing all of them, some of them maybe more than once since you can implement the generic strongly typed versions as well as the non-generic versions, additionally you can implement more than one of the generics. Let's take an example scenario, let's say a webshop where you can buy credits with which you can buy something else (stock photo sites often use this scheme). You might have a class "Valuta" and a class "Credits" that inherit form the same base. Valuta has some nifty operator overloads and comparison routines that allow you to do calculations without worrying about the "Currency" property (adding pounds to dollars for example). Credits are allot simpler but have some other distinct behavior. Wanting to be able to compare these with each other, you could end up implementing IComparable as well as IComparable and the other variants of comparison interfaces on both (even though they use a common implementation whether it be in the base class or somewhere else). When implementing serialization, ISerializable, IDeserializationCallback get implemented. Then implementing undo-redo stacks: IClonable is added. IsDirty functionality: IObservable, INotifyPropertyChanged. Allowing users to edit the values using strings: IConvertable... The list can go on and on... In modern languages we see a different trend that helps separate these aspects and place them in their own classes, outside the core class. The outside class or aspect is then associated with the target class by using annotation (attributes). Often it is possible to make the outer aspect classes more or less generic. The use of attributes (annotation) is subject to reflection. One drawback is minor (initial) performance loss. An (often emotional) drawback is that principles such as encapsulation need to be relaxed. There are always other solutions, but for every nifty solution there is a tradeoff or a catch. For example, using an ORM solution might demand all properties to be declared virtual. Serialization solutions might demand default constructors on your classes. If you are utilizing dependency injection you might end up implementing 23 interfaces on a single class. In my eyes, 23 interfaces does not have to be bad by definition. There might a well thought out scheme behind it, or some principle determination such as avoiding the use of reflection or extreme encapsulation beliefs. Whenever switching a job, or having to build on an existing architecture. My advice is to first get fully acquainted, do not try to refactor everything too quickly. Listen to the original developer (if he's still there) and try to figure out the thoughts and ideas behind what you see. When asking questions, do so not for the sake of breaking it down, but to learn... Yes, everyone has their own golden hammers, but the more hammers you can collect the easier you will get along with fellow colleagues. |
|||
|
|
|
"Too many" is subjective: programming style? performance? conformance to standards? precedents? just plain sense-of-comfort/confidence? So long as your code behaves right and presents no maintainability issues, 23 could even be the new norm. Someday I could then say, "You can do an excellent piece of work with 23 interfaces, see: Jonas Elfström". |
|||
|
|
|
I would say that the limit should be a smaller number than 23 - more like 5 or 7, (So altogether, N + any number of inherited interfaces, where N <= 7.) If your class implements too many interfaces, it is probably a god-class. |
|||
|
|

