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".
Behavior in this context is refering to semantic behavior. For example, a Property on a class (i.e. attribute on a domain object) that is used to uniquely identify it has a behavior. While this is not represented in code directly. The expected behavior is that there will not be any duplicate values for that property. Something such as an Address which may have its own identity, but does not exist outside of the context of a Person Entity should still be moved out into it's own object. Thus promoting the Entity into an Aggregate Root.
Furthmore, a property such as Age has no context outside of a Person Entity, and as such, makes no sense to move into a different object. The context would be lost, and therefore you can safely determine that it is a value that is essential to the Person Entity. You could not locate the value otherwise. However that information could easily be stored in a separate location that the unique identifier, hence the confusing reference to behavior. Age could be a lazy loaded value.
So to answer your question. No, it does not violate the Single Responsibility Principle. It is mearly stating that a Person should have only person stuff, and not something like Address, which is more complex and related to a person, should exist as its own entity.
You could easily have operations specific to Address such as verification that it is a valid address. You may not know that at design time, but this whole concept is to break down objects into their smallest parts so that something like this is relatively simple when done after the fact.
Update:
1) In most cases this identity validation is done upon saving an object out to a data store. Which means that the code representing the entity validation exists, but it exists elsewhere. It usually exists with the code that is responsible for issuing the identity value. Which is why I state that the uniqueness is not represented directly in the code for the entity.
2) The correct statement would be that Age
is an attribute that has behavior. You would need to document the fact that Age is lazy loaded so that a developer consuming that property can make an accurate decision on how to consume that property
3) DateOfBirth
usually is a different object; A date object that already has predefined operations on it. In some languages the date object already has a whole domain model defined on it. For example in c# you can specifiy the timezone, if the date is UTC, add and subtract dates to get a timespan. So your assumption about moving DateOfBirth
would be correct.
4) If the only thing that MyEntity
does is delegation and cooridination then no it does not violate SRP. Its single responsibility is to delegate and coordinate and is refered to as the Facade pattern
Best Answer
As with any rule, I think the important thing here is to consider the purpose of the rule, the spirit, and not get mired in analyzing exactly how the rule was worded in some textbook and how to apply that to this case. We don't need to approach this like lawyers. The purpose of the rules is to help us write better programs. It's not like the purpose of writing programs is to uphold the rules.
The purpose of the single-responsibility rule is to make programs easier to understand and maintain by making each function do one self-contained, coherent thing.
For example, I once wrote a function that I called something like "checkOrderStatus", that determined if an order was pending, shipped, back-ordered, whatever, and returned a code indicating which. Then another programmer came along and modified this function to also update the quantity on hand when the order was shipped. This severely violated the single responsibility principle. Another programmer reading that code later would see the function name, see how the return value was used, and might well never suspect that it did a database update. Someone who needed to get the order status without updating the quantity on hand would be in an awkward position: should he write a new function that duplicates the order status part? Add a flag to tell it whether to do the db update? Etc. (Of course the right answer would be to break the function in two, but that might not be practical for many reasons.)
On the other hand, I wouldn't nitpick what constitutes "two things". I just recently wrote a function that sends customer information from our system to our client's system. That function does some reformatting of the data to meet their requirements. For example, we have some fields that may be null on our database, but they don't allow nulls so we have to fill in some dummy text, "not specified" or I forget the exact words. Arguably this function is doing two things: reformat the data AND send it. But I very deliberately put this in a single function rather than having "reformat" and "send" because I don't want to ever, ever send without reformatting. I don't want someone to write a new call and not realize he has to call reformat and then send.
In your case, update the database and return an image of the record written seem like two things that might well go together logically and inevitably. I don't know the details of your application so I can't say definitively if this is a good idea or not, but it sounds plausible.
If you are creating an object in memory that holds all the data for the record, doing the database calls to write this, and then returning the object, this makes a lot of sense. You have the object in your hands. Why not just hand it back? If you didn't return the object, how would the caller get it? Would he have to read the database to get the object you just wrote? That seems rather inefficient. How would he find the record? Do you know the primary key? If someone declares that it's "legal" for the write function to return the primary key so that you can re-read the record, why not just return the whole record so you don't have to? What's the difference?
On the other hand, if creating the object is a bunch of work quite distinct from writing the database record, and a caller might well want to do the write but not create the object, then this could be wasteful. If a caller might want the object but not do the write, then you'd have to provide another way to get the object, which could mean writing redundant code.
But I think scenario 1 is more likely, so I'd say, probably no problem.