Sign in to follow this  
ChaosEngine

Inheritance vs Composition

Recommended Posts

Prevailing modern wisdom (both on these boards and in the wilds of the internets) is that composition is preferable to inheritance for code re-use. From what I gather
Quote:
Inheritance should be used to describe a common interface ala the LSP. Composition should be used to duplicate common implementation across classes.
So in code terms
// pseudo -code
class Vehicle
{
    public Move()
}

class Car : Vehicle
{}
is ok, but
class PoweredVehicle : Vehicle
{
}

class Car : PoweredVehicle 
{
}
would be better described as
class Car
{
    private Engine engine;

    override Move()
    {
        engine.Run();
        // blah blah make car move
    }
}
With me so far? (Please correct me, if I'm mis-stating the case) I get the argument that this is more flexible (I can put an Engine in an immobile object for instance), but my issue is that while composition with Engine saves us some code re-use, I still have to remember to give Tank, Bus, Motorcycle and TurboFrobnicator their own engine along with hooking up the engine in Move. "So what? Stop being so bloody lazy and add the damn engine. Good design sometimes takes more code." And that's a fair point, but the problem is that everytime I have more code to write (esp boilerplate) it's a potential source of bugs. If the interface of engine changes, I now have multiple places I need to change. I'm not saying inheritance is a better way, but it does at least save me from the issue outlined above. Thoughts, criticisms, suggestions and condescending pats on the head all welcome.

Share this post


Link to post
Share on other sites
I'd suggest that you do some further reading up on the Liskov Substitution Principle, because it pretty much perfectly covers the case you describe.

A car "is a" powered vehicle which "is a" vehicle; this is a perfectly acceptable use of inheritance. A powered vehicle "has a(n)" engine, which means that adding an engine member to the class (and adding any associated interface) is a perfectly valid use of composition.

You may also want to look into so-called "component based" architectures, which are sort of a late-binding form of composition. In large systems, components can radically reduce the complexity of your code without sacrificing anything in terms of feature richness, while still maintaining clean, loosely-coupled code.


Much of the time, the solution that generates the least code is likely the best option, although exceptions do of course exist. Good architecture should almost never significantly increase your implementation complexity or code size.

Share this post


Link to post
Share on other sites
Usually some kind of data driven approach to entity creation is a prerequisite to this kind of thing. Beyond simple composition is the component based entity type of design which pretty much requires you be able to build components from some kind of descriptor.

For example, using the entities as a bag of components type of system, you would request a Tank which would create for you an entity with the necessary components (Model, Physics, Armament, Engine, etc) already attached.

Share this post


Link to post
Share on other sites
Quote:
Original post by ChaosEngine
I get the argument that this is more flexible (I can put an Engine in an immobile object for instance), but my issue is that while composition with Engine saves us some code re-use, I still have to remember to give Tank, Bus, Motorcycle and TurboFrobnicator their own engine along with hooking up the engine in Move.

"So what? Stop being so bloody lazy and add the damn engine. Good design sometimes takes more code."

And that's a fair point, but the problem is that everytime I have more code to write (esp boilerplate) it's a potential source of bugs. If the interface of engine changes, I now have multiple places I need to change.
Dunno about C#, but other languages have things called "mixins" that might help, and C++ has some options for cutting down on boilerplate related bugs:
template<class Self>
class HasEngine : public virtual IMovable
{
private:
Engine engine;
virtual void Move()
{
engine.Run();
Self::OnMove();
}
};
class Car : public HasEngine<Car>
{
public:
void OnMove() {...}
};

#define DECLARE_CLASS_HAS_ENGINE( ONMOVE ) \ 
private: \
Engine engine; \
virtual void Move() \
{ \
engine.Run(); \
ONMOVE \
} //
class Car : public IMovable
{
DECLARE_CLASS_HAS_ENGINE( OnMove(); )
public:
void OnMove() {...}
};

Share this post


Link to post
Share on other sites
Thanks for the replies all, esp ApochPiQ.

Quote:
Original post by ApochPiQ
Much of the time, the solution that generates the least code is likely the best option, although exceptions do of course exist. Good architecture should almost never significantly increase your implementation complexity or code size.


I tend to agree with this which is why I posted this topic.

wild_pointer, an entity driven approach isn't really appropriate for what I'm doing at the moment, although given my example code, I'd agree that it would be a good solution in that case.

What I'm actually doing is not game-related.

I'm writing a WPF frontend for a set of webservices. The webservices operate on "send what's changed" principle. I'm required to track the users changes to properties on an object. I have a ChangeList class which hooks up to a client side object and tracks the changes in the object (essentially a list of property names). I was considering creating a ClientObject base that has a ChangeList and would save me the wire up on each class, but I wasn't sure it this was a good idea.

edit: oops, important difference between "is" and "isn't" [grin]

Share this post


Link to post
Share on other sites
Adding an engine to every car is desirable if you have more than one kind of engine, or say suspension. Otherwise you start getting strange inheritance hierarchies like

Vehicle -> PoweredVehicle -> Car -> CarWithV12AndCustomSuspension -> Diablo
Vehicle -> PoweredVehicle -> Car -> CarWithCustomBuiltFluxCapacitorAndCustomSuspension -> Delorian
Vehicle -> PoweredVehicle -> Car -> CarWithFourCylinderAndCheapSuspension -> Civic

With composition, you can stop at car. Creating different cars is just a matter of writing factory methods (Omitting smart pointers for brevity):

Car* CreateCivic()
{
return new Car( new FourCylinderEngine(), new CheapSuspension() );
};

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this