Introduction
Composition and inheritance are two major concepts in object-oriented programming (OOP) that allow for creating complex types.Inheritance is a mechanism where you can derive a class from another class for a hierarchy of classes that share a set of variables and methods. The derived class (child) inherits the members of the base class (parent) and can access them. Inheritance supports the concept of "is a" relationship.
Composition, on the other hand, is a method to combine simple objects or data types into more complex ones. In composition, instance or class objects are are used in different classes. Composition supports "has a" relationship.
Here are some reasons why composition has benefits over inheritance:
- Increased Flexibility: In composition, a class can control the visibility of other objects. So, we can decide when and how a client class can access the composed class. we reference the composed object via a exported member variable or expose its composable features via dedicated interface methods.
- Reduced Dependencies: In composition, objects can be replaced at runtime. We can change the behavior of an object at runtime by changing its members, which is impossible with inheritance. We can go even further and store the composed class at class member level, and the instance on instance member level. So by changing the reference class member we can change behavior of newly created instances.
- Reuse of Code: Code can be reused by adding a reference to the class that has the required functionality rather than inheriting from it. This allows adding new features at different leaves of the inheritance tree, allowing code reuse in a more wide spreaded and better isolated manner.
- Reduced Fragility: Subclasses depend heavily on the implementation details of their parent class, thus, the superclass changing might break the child class.
Example
To illustrate this, let's use an example in Xbase++. Imagine you're designing an application that simulates a zoo. You have classes like Animal, Lion, Tiger, Bird and Zoo.In an inheritance model, you might start by subclassing Animal to create Lion, Tiger and Bird. This can be problematic if the Animal superclass changes, or if you want a Lion that behaves differently than a regular Animal.
Xbase++:
CLASS Animal
EXPORTED:
METHOD Eat
METHOD Sleep
ENDCLASS
CLASS Lion FROM Animal
EXPORTED:
METHOD Roar
ENDCLASS
CLASS Tiger FROM Animal
EXPORTED:
METHOD Prowl
ENDCLASS
CLASS Bird FROM Animal
EXPORTED:
METHOD Fly
ENDCLASS
In a composition model, Animal would have objects of other classes like FeedingBehaviour, SleepingBehaviour etc. This allows us to create Lion, Tiger and Bird classes with different behaviors without worrying about changes in the Animal superclass.
Xbase++:
CLASS FeedingBehaviour
EXPORTED:
METHOD Eat
ENDCLASS
CLASS SleepingBehaviour
EXPORTED:
METHOD Sleep
ENDCLASS
CLASS Animal
EXPORTED:
VAR Feeding
VAR Sleeping
ENDCLASS
CLASS Lion FROM Animal
EXPORTED:
METHOD Roar
ENDCLASS
CLASS Tiger FROM Animal
EXPORTED:
METHOD Prowl
ENDCLASS
CLASS Bird FROM Animal
EXPORTED:
METHOD Fly
ENDCLASS
In the composition model, each animal can have its own distinct behavior for eating and sleeping. For example, a bird might have different eating and sleeping behaviors compared to a lion, and these can be set independently without any inheritance-related issues.
Criteria
Keep in mind the following factors when deciding between composition and inheritance in Xbase++:- Is-a vs Has-a Relationship: If the relationship between two entities can be expressed as "is a," then inheritance might be the better choice. For instance, in the context of our zoo, a Lion is an Animal, so Lion inheriting from Animal makes sense. On the other hand, if the relationship is better expressed as "has a," then composition is typically more appropriate. For instance, an Animal has a FeedingBehaviour and SleepingBehaviour, which makes these better candidates for composition.
- Code Reusability: Composition can allow for better code reusability because you can use an object of one class in multiple other classes. For example, different types of Animal objects can use the same FeedingBehaviour or SleepingBehaviour object.
- Type of Inheritance: While Xbase++ does support multiple inheritance, you should still consider whether multiple inheritance is the best solution for your problem. Multiple inheritance can sometimes lead to problems like the Diamond Problem, where a class inherits from two classes that have a common base class. In such cases, it can be unclear which parent class a method or property should be inherited from. Composition, on the other hand, avoids this issue.
- Flexibility: Composition provides greater flexibility because you can change behavior at runtime by changing the objects a class is composed of. For example, you could change an Animal's FeedingBehaviour at runtime without changing the class definition.
- Dependencies: Inheritance can lead to high coupling between classes because the subclass depends on the implementation of the superclass. If the superclass changes, it can break the subclass. With composition, objects are less coupled because they interact through their interfaces, and changes in one class don't necessarily affect others.
- Design Principle: The principle of composition over inheritance suggests that it's safer to use composition to reuse code between classes because it leads to a less complicated and more flexible design.
Summary
Composition can often provide a better design solution than inheritance as it leads to less coupling between classes, more flexibility, and code that's generally easier to maintain and understand. While multiple inheritance gives Xbase++ an additional level of complexity and flexibility, it's still often a good idea to favor composition because it provides more flexibility and fewer dependencies between classes.However, the choice between using inheritance and composition often depends on the specific requirements of your project.