If you have a class which inherits from two distinct classes, does not this mean that your subclass automatically does (at least) 2 things, one from each superclass?
I believe there is no difference if you have multiple interface inheritance.
To be clear, I believe that if subclassing multiple classes violates SRP, then implementing multiple (non-marker or basic interface (e.g. Comparable)) interfaces violates SRP too.
9
In a very narrow sense, the answer is “Yes”: assuming that your base classes or interfaces are designed for a single purpose, inheriting both of them does create a class with multiple responsibilities. However, whether or not it is “a bad thing” depends on the nature of the classes or interfaces that you are inheriting.
You can partition your classes and interfaces into two major groups – the ones addressing the essential complexity of your system, and the ones addressing its accidental complexity. If you inherit from more than one “essential complexity” classes, it is bad; if you inherit from one “essential” and one or more “accidental” classes, it is OK.
For example, in a billing system you could have classes for representing invoices and billing cycles (they address the essential complexity) and classes for persisting objects (they address the accidental complexity). If you inherit like this
class BillingCycleInvoice : public BillingCycle, public Invoice {
};
it is bad: your BillingCycleInvoice
has a mixed responsibility as it relates to the essential complexity of the system.
On the other hand, if you inherit like this
class PersistentInvoice : public Invoice, public PersistentObject {
};
your class is OK: technically, it services two concerns at once, but since only one of them is essential, you can write off inheriting the accidental one as the “cost of doing business”.
2
The SRP is a guideline to avoid god-classes, which are bad, but it also can be taken too literally and a project starts balloon with tons of classes that can’t really do anything without a handful being combined. Multiple inheritance/multiple interfaces can be a sign a class is getting too big, but it could also be a sign that your focus is far too granular for the task at hand and your solution is over-engineered, or it could simply be a perfectly valid use case for multiple inheritance and your worries are unfounded.
Software design is as much art as science, its a balancing act of many competing interests. We have rules to help avoid things we know are to far in one direction that cause problems, but those rules can just as easily take us to a place that is just as bad or worse than what we were trying to avoid in the first place.
Somewhat. Let’s focus on the main principle for SRP:
A class should only have one reason to change.
Multiple inheritance doesn’t force this, but tends to lead to it. If the class overrides or implements its base classes, that tends to be more reasons for it to change. In this way, interface multiple inheritance tends to be more troublesome than class inheritance. If two classes are inherited but not overridden, then the reasons to change exist in the base classes not the new class.
The places where multiple inheritance does not violate SRP is when all but one of the base types aren’t something that the class is implementing, but act as a trait that the class happens to have. Consider IDisposable
in C#. Things that are disposable don’t have two responsibilities, the interface just acts as a view into classes that share the trait but have decidedly different responsibilities.
Not at all. In Java, you can have an interface that represents some sort of domain object–a Foo, for example. It may need to be compared to other Foo objects, and so it implements Comparable (with the comparison logic externalized in a Comparator class); it may be that this object also needs to be Serializable, so that it can be transported across the network; and it may need to be Cloneable. Thus the class implements three interfaces but does not have any logic within to support them beyond that supported by Foo.
That said, it’s silly to take the SRP to extremes. If a class defines more than one method, is it violating the SRP? All Java Objects have a toString() method and an equals(Object) method, which means EVERY object in Java is responsible for both equality and self-representation. Is that a bad thing?
Not in my opinion. To me, a single responsibility is “model a user of my application”. I may need to deliver that data via a web service, and store it in a relational database. I could provide that functionality by inheriting a couple of mix-in classes.
That doesn’t mean the class has three responsibilities. It means that part of the responsibility to model a user requires supporting serialization and persistence.
I guess it depends on how you define the responsibility. In the classic iostream example it doesn’t violate the SRP. The IOstream is responsible for managing one bidirectional stream.
After you run out of primitive responsibilities you move on to more generic high level responsibilities, after all how do you define the responsibility of your main entry point? Its responsibility has to be ‘be the main entry point’ not ‘everything my app does’ otherwise it is impossible to not violate the SRP and produce an application.
Not at all. Let’s say you have a button in the UI, and it’s responsibility is to start the process of deleting an address in the user’s address book.
The button also has the responsibility to process mouse clicks, to redraw itself when needed, change its appearance while highlighted, hide the background behind it, show or hide itself, change its Color or title as directed and so on. That’s at least a dozen responsibilities and violations of the dreaded “single responsibility principle”.
But that’s not how it works! Your button has one responsibility. Multiple inheritance has nothing to do with this.