By using composition and interfaces instead of inheritance, class relationships become more explicit and the design becomes more flexible.
Inheritance is useful for centralizing functionality and enabling polymorphism at the same time. However, inheritance is often used for centralization or polymorphism and not both. A design that uses CompositionInsteadOfInheritance and InterfacesInsteadOfInheritance? make class relationships explicit: Either you want polymorphism, or shared functionality.
Using only interfaces and composition, code becomes easier to ReFactor: There is no longer a static link between classes and their super classes. And references to shared functionality becomes explicit rather then relying on inheritance fall-through rules.
Impossible. My design requires class inheritance.
Any class inheritance can be changed to an interface inheritance and composition relationship: Create a common interface and refactor common functionality. See PolymorphismAndInheritance.
This means I would have to do delegation everywhere.
Yes. Class inheritance does this for you implicitly, but composition makes the relationships explicit.
On the other hand delegation can be a real pain in some languages. C++ (and probably Java) delegation involves copying each public method signature and writing a little method body that forwards the call. It also means you maintain two instances of the method when something changes, like the constness of the method or the return type or the constness of a parameter etc., etc... Any changes are then spread across four files: two .h files and two .cpp files.
[edited] Not only does delegation in C++ and Java mean writing more code, it is also not as performant as class inheritance. Implicit delegation by inheritance needs constant time, explicit delegation is linear.
In PythonLanguage, on the other hand, delegation can be achieved with as little as one extra method to delegate to one or more classes. Altering the number of parameters of a delegated method often requires a change to only one module.
I would have to make an interface for every class.
No. You would only create interfaces where you want polymorphism.
I need protected methods. This makes them useless.
Right - that's a problem. The best way I can argue this is that protected methods are unnecessary unless you are writing a library of code for another group to develop against. And in this case you may only want to give them access to an API defined by a set of interfaces rather then to your underlying classes. In this way, all class methods are protected methods, and interfaces methods are public methods.
Alternate response: Protected Methods are no longer necessary. Instead of providing the implementation in the base class and using it in a higher class, one implements the methods as public methods in a support class. The user classes contain the support class as a private member. This has no affect on the external, public interface of the child class and avoids a lot of dependencies that result from protected class declarations.
(See also: MethodsShouldBePublic)
How do I extend classes?
Implement the interface and delegate to the class that you would have extended. See DelegationInheritance.
One minor problem: how does the delegated class delegate back, since it loses the polymorphic dispatch on this (self)?
The single benefit cited here is explicit delegation, which may or may not save you time refactoring. YouArentGonnaNeedIt. If inheritance is the SimplestThing, do that. If it ceases to be the simplest thing, then refactor to CompositionInsteadOfInheritance, not before. In my experience, the time saved with implicit delegation is usually greater than the rigidity of inheritance. When it's not, that's when I use composition.
[edited] Inheritance done by anyone with half-decent skill often increases readability and reduces SpaghettiCode. For more discussion of this, see RavioliCode
Isn't this what we have to do to get InheritanceInVbClassic? And everyone said how sad we were.
Same for COM, which has no inheritance. CORBA folks loved bashing COM about this. Interestingly, Microsoft's new component model, .Net, has inheritance.
CORBA does not have class inheritance. It only has interface inheritance. COM also has interface inheritance (e.g. all interfaces inherit IUnknown). The only advantage CORBA has over COM is multiple interface inheritance; COM uses the QueryInterface method to implement multiple interface inheritance.
How do I create an Aggregate Class?
Often times I need to create a large class that is just the aggregation of several smaller classes. For example, a Person class may consist of a Name class and an Address class. My application may wish to organize people by last name in some cases and state of residence in others. Having a Person class inherit directly from a Name class and an Address class is the simplest solution. The alternative becomes having the Person class inherit a Name interface and contain an embedded Name class, and also inherit an Address interface and contain an embedded Address class, with all of the necessary delegation.
"Having a Person class inherit directly from a Name class and an Address class is the simplest solution."
Is it? I would have thought creating an iterator or comparator for each sort order would be much simpler. -- JimArnold
But how do you link the two classes? It does no good to sort the addresses if I can't get to the corresponding names and vice-versa.
If Person has-a Name and Address, your link is the Person itself. This seems trivial to me - maybe I'm missing something fundamental in your argument? -- JimArnold
Inheritance exposes the Person interface so you can perform Person operations without having to create a gazillion delegation methods.
But why do you need delegation methods? If you're going to tie Person to Name and Address via an abuse of inheritance, why not abuse the LawOfDemeter instead and reference Name and Address through Person?
class Person { public Name name; public Address address; }-- JimArnold
Pick your form of SelfAbuse? then :-) The advantage of inheritance is that you can override methods. With the direct access, there's no way for a container to add an interceptor layer between itself and what it contains.
private Person[] myPeople = new Person[10]; public void Persist() { for each (Person aPerson in myPeople) { try { aPerson.Persist(); } catch (System.Exception anException) { // oops! handle the problem. } } }}
class Person {
private NameWithoutSpecialCharacters? myName; private AddressWithMaybeSomeSpecialProcessing? myAddress; public string Name { get { return myName.Value; } set { myName.Value = value; } } private bool IsValidForPersistence? { get { // whatever checks need to be done to validate this Person go here. // (_not_ including special character checks - those go in // NameWithoutSpecialCharacters? } } public void Persist() { if (IsValidForPersistence?) { // write this object to a file. } else { raise System.Exception; } }}
class Name {
private string myName; protected virtual bool IsValid(string aName) { return true; } public string Value { get { return myName; } set { if (IsValid(value)) { myName = value; } else { raise System.Exception; } } }}
class NameWithoutSpecialCharacters? : Name // NameWithoutSpecialCharacters? inherits from
// Name{
protected override bool IsValid(string aName) { if (aName contains special characters) { return false; } else { return true; } }}
The best reason for having Person inherit from Name would be so that you could use an instance of Person where an instance of Name was expected. But saying "thePersistentFile.Name = Person" is silly. Why use inheritance here?
Polymorphism wouldn't be the primary reason for Person to inherit from Name. The reason would be to provide the name interface without having to write a bunch of delegation methods in such away that a layer of indirection by overriding some methods can be added.
What delegation methods are you talking about? Look back at my example again. In the Person class, I just made the Name and Address fields public to emphasize that no further getters/setters are really necessary in that class. You've mentioned before wanting to override methods in the base Name interface. In my example, that code exists in the NameWithoutSpecialCharacters? class. Exactly the same stuff you already said _needs_ to exist. What extra methods are you talking about? There is none.
I would never make data public so perhaps there's a difference there. The methods would be to set and get the name that would delegate to the Name methods.
Ok. I changed the Person class back to the original form I presented, with the myName and myAddress fields declared as private. I also added a public Name property to demonstrate the delegation that's giving you problems. Five lines of code. You say below that "In this case, [inheritance] buys you a lot." You and I have a different definition of "a lot".
I would need to override the set to check for DOS-related characters, not special characters in general. NameWithoutSpecialCharacters? is wrong because it doesn't capture what is going on.
It's not wrong; it's just pseudo-code. You earlier used the phrase "special characters that DOS doesn't like". I just tried to condense that somewhat to make the class name less unwieldy. Call it NameWithoutSpecialCharactersThatDosDoesntLike? if you want.
You've said a couple of times in this thread that, if you use inheritance, you have to override one of the methods of the Name interface inside the Person class in order to implement the character elimination logic. That is exactly what goes in this class. In the IsValid method, to be exact.
I added the base Name class to my example above to demonstrate that the definition of NameWithoutSpecialCharacters? involves overriding just the method that validates the string being assigned to the Name object. This is exactly the same logic you would have to add to you hybrid Person class, its just located in the class responsible for implementing special names.
It's not my fault the only way to do this in C++ requires ISA. I take that back. As person has a name and if I want to pass that to something that expects a name, ISA makes that very convenient. It seems you are being slavish to reality. Programs aren't reality. There's no reason not to say Person ISA Name if it buys you something. In this case it buys you a lot. A language with different capabilities would cause me to make different choices.
"Polymorphism wouldn't be the primary reason for Person to inherit from Name." ... MakeReservation?(const Name& customerName) {} Person p("fred"); MakeReservation?(p);
To pick a nit, you contradict yourself. Being able to use Person objects polymorphically in calls to MakeReservation? is exactly the reason you've put for for having Person inherit from Name.
"As person has a name and if i want to pass that to something that expects a name, ISA makes that very convenient."
Can you give me an example of this convenience? Some code snippet that shows me how having Person inherit from Name is more "convenient" than the sample code I wrote above? To me, it looks like no matter whether you use inheritance or containment/composition, as in my example, in either case you can say "thePersistentFile.Name = aPerson.Name". What else do you need? What benefit does inheritance provide? What code does it prevent you from having to write?
MakeReservation?(const Name& customerName) {}
Person p("fred"); MakeReservation?(p);
Ok, we're just never going to agree on this. I honestly don't mean this as a flame, but in my mind, this is simply lazy programming. You're intentionally misrepresenting the relationships of your classes, pretending a Person is a Name, just so that you can type "p" instead of "p.name". Why don't you have MakeReservation? accept a parameter of type Person rather than Name, and avoid the whole issue?
But why do you need delegation methods? If you're going to tie Person to Name and Address via an abuse of inheritance, why not abuse the LawOfDemeter instead and reference Name and Address through Person?
class Person { public Name name; public Address address; }Why is this an "abuse of inheritance?" The approach above does not allow me to use sort and search methods created for collections of Name objects or Address objects. If I want to list the names of people with an address in the state of Nebraska, I have the following options,
1) Use an existing search method based on collections of Address objects to find all Address objects with the state set to Nebraska and then do a search through my collection of Person objects to match the Address objects to the Person objects and then retrieve the Name objects. 2) Create an address search method for Person objects that duplicates the operation of the search method written for Address objects and continue to maintain duplicate code. 3) Have a Person class inherit from both the Name class and the Address class, allowing all operations written for the lower level Name and Address classes apply directly to the Person class as well.
OK, can we start signing our comments? This is getting confusing. There are (at least) three people talking here. To answer the above, the reason it's an abuse of inheritance is because you're enforcing Person's interface in the wrong way. If Address has an IsInState?(State state) method, and you want the same method on Person, factor it into an interface that both classes can implement (ILocatableByState or whatever).
I can understand your argument that Person is-a Name and Address, but I think the semantics are wrong. Person is-composed-of a Name and Address, and it is LocatableByState? (as is an Address). -- JimArnold
''And what is wrong with implementing composition by inheritance if it gives you demonstratable benefits when building a program? We are not talking in the abstract here. We are talking about creating a program to do something. Inheritance has benefits when implementing composition. Why not take advantage of that?''
I have yet to see any demonstrable benefits of using inheritance in this situation.
''It is often very hard to demonstrate something to someone who doesn't agree in the first place. For me, not having to delegate (or expose public data), having the ability to silently extent functionality, the ability to override just the methods I want without interposing another class, and the ability to use ISA to simplify argument passing, are all reasons enough. It is the simplest thing. Composition is much more verbose and complex and has no demonstrable benefits.''
Let me take one last stab at this:
Delegation - if you use composition, yes you'll have to write delegation methods. But at five lines per, as in my example above, if this _really_ a big burden? I used to program in VB6, and even in that environment, I was able to write an addin that allowed me to automatically generate the delegation code.
"Silently extending functionality" - I'm not sure what you mean by this.
Overriding methods without adding another class - In my example, the overriding you'd do in the NameWithoutSpecialCharacters? class is exactly the same as you'd have to do in your Person class? And it associates rules for validating names with a class that defines a type of name. Why is that a problem? See FearOfAddingClasses, perhaps?
Simplified argument passing - You are only saving yourself five characters worth of typing. And you're presenting a conundrum to any future maintenance programmer. Your MakeReservation? routine takes a Name argument, but you pass it a Person. There's no reason inherent in your problem domain (at least that you've told me) why Person should inherit from Name. Indeed, you're only doing it for coding convenience. That would definitely confuse me, if I were the maintenance programmer, possibly making me waste time chasing a RedHerring, instead of the real bug I was after.
"Composition is much more verbose and complex..." - I vehemently disagree with this. Composition is only slightly more verbose, at worst. And the additional code is very simplistic. Five simple lines, in my example. But that's the lesser issue.
Composition is less complex because the code says exactly what its doing. A person has a name, so a Person class has a field of type Name. You want to sort Person objects according to their names, so you have a sort routine that accepts a collection of Person objects, accessing and comparing their name fields. Given just a description of the problem ("sort these people according to their names"), there's no way to reason your way to an explanation of why Person should inherit from Name. Why would you purposely undermine the ability to reason about your solution in the same way you reason about your problem?
The analysis domain and the implementation domain are fundamentally different. One is the best way to solve a problem and the other is the best way to implement the solution to the problem. If you don't make this distinction then you don't and we just do things differently. From my experience all the extra work is a nightmare to maintain without a sufficient reason to do it. There is nothing compelling in your arguments.
Nor in yours. Yes, we simply see the world differently. C'est la vie.
"Silently extending functionality" means that when interfaces are used i can add new functionality by adding a method and I don't break anyone who doesn't use it. In composition i would have to add a delegator to every class just to pass the functionality through to a low layer who may use it.
In regards to your sorting issue, the basic problem is that your code suddenly changes its mind about what is important in the world. From what you've told me, manipulating Person objects is the primary purpose of your code. It creates a collection of Person objects based on data from an outside source, persists those Person objects to files, and now wants to sort those Person objects based on their names or addresses.
But the code that does the sorting suddenly takes the view that Name or Address objects are its primary focus. It literally sorts collections of Name or Address objects, then has to somehow link those objects back to their corresponding Person objects. This change of focus is causing your problems.
You really need sort (or search) routines that operate on collections of Person objects, sorting them based on the value of their Name fields. By keeping the code focused on operating on Person objects, you eliminate the need for this "a Person is-a Name" fiction.
Or I use the existing search and sort operations. Do you have a stronger argument beyond some personal intellectual purity? Sure, we could write (and rewrite) additional code to accomplish this, but why?
I think the core problem is "search methods created for collections of Name objects". Why isn't it simply "search methods created for *collections*.", period? Using the convention of Java's collection library, you would only need *comparators* of Name objects and use the library search methods to do the searching (similar for sorting). So to search/sort the collection of Person objects based on name, just create a new comparator for Person objects which delegate to the Name comparator. -- OliverChung
Indeed. Excellent point.
Look at this from the perspective of the Address class. We have multiple things that have addresses. We would like to be able to use and add address searches for all of these higher level classes. Having to add a new address search/sort and the delegators to all possible user classes is difficult in maintenance. It is also frustrating to have an expected search/sort fail because of a missing delegator, and it becomes tempting to add a new comparator at the higher class level. Remember, we are trying to simplify software.
Nor in yours. Yes, we simply see the world differently. C'est la vie.
I don't think there is a compelling argument either way. But I'm not trying to tell that world there is only one way, as is this page.
Unfortunately this discussion doesnt seem to address the concept of Composition and Interfaces very well, and focuses more on what is (and has been mentioned) Convenience Inheritance. I think the discussion about when to use composition instead of class inheritance covers a much wider problem space than the one presented here. Maybe this should be given a new location, maybe called ConvenienceInheritance?, possibly extended to ConvenienceInheritanceInsteadOfComposition?. I think the idea of TaxonomicalInheritance?, with regards to using composition/delegation would be more enlightening for this topic (maybe its been presented elsewhere but I havent seen it so far).
See: WeDontUseInheritanceEnough?
The ScarletLanguage uses an object model that is exactly like this except that the delagation is handled automatically. Objects are composed of one or more implementations that implement interfaces. There is no implementation inheritance and the aggregated implementations are treated as a single object. This leads to very fine grained interfaces and implementations that are narrowly tailored to one purpose. So, it's easy to assemble new types by throwing together implementations or to customize existing types (even the standard library types) by adding a new implementation or by replacing an old one.