Choosing the right tool for any particular context is important for writing clean, maintainable code. The language we use to describe the relationships should guide when you use each technique. Inheritance should only be used to model βis-aβ relationships. In situations where βhas-aβ is the better description, composition should be preferred.
Say there is an existing class Person and we are making a BankAccount. The BankAccount belongs to a particular person, and we would like to represent this with an explicit relationship. Does it make sense to say a BankAccount is-a Person? Not in the least. This is clearly a spot where inheritance should not be used, even if it would accomplish the technical goal of letting us use existing Person code inside of BankAccount.
Even in situations where inheritance might seem appropriate, composition may still provide a better design. Consider representing various sales transactions. Some are Phone, some are Online, and others are InStore. Each transaction involves payment that is either Cash, Account, or Credit.
This is awful. We have 13 classes to represent the different types. And CreditPhone and CreditOnline will probably have code in common. But there is no good place to put that common code. The only parent they have in common is Order and that is not the right place for credit card payment logic.
Multiple inheritance might sound like a solution to that issue. It would let us put common payment logic in a shared parent class for all Credit orders by having a Credit class that they all inherit from. But the class explosion from this design only gets worse. Not only do we have more intermediate classes, we still need classes like CreditPhone to unite the two different aspects (order method and payment method).
Now letβs consider how we might build this with composition. We can have one class Order that has-a instance of PaymentMethod and OrderMethod as members. This way, we can represent all the possible transaction types without an explicit class for each. To make a Order that represent an in store, cash order we would first construct a Cash payment method object and an InStore order method object. We would then use them to construct an Order that had the two other objects as members.
A common piece of advice is βfavor composition over inheritanceβ. Composition tends to allow more flexible relationships and it avoids the class explosion problem. Just because you could think of a design problem in terms of is-a does not mean you have to use inheritance.