Composition
Composition is a design principle in object-oriented programming where a class is composed of one or more objects from other classes, rather than inheriting from them. This "has-a" relationship between the composite class (the owning class) and the component class (the owned class) implies that the composite class has strong ownership and control over the component.
Composition in Object-Oriented Programming (OOP) is another type of "has-a" relationship, similar to aggregation, but with a key difference: in composition, the parts cannot exist independently of the whole.
To explain this in simple terms, think of a bird and its wings. A bird is composed of various parts, including its wings. Wings are an integral part of a bird; they don't exist separately from the bird. If the bird ceases to exist, so do its wings. This is the essence of composition.
In programming terms, composition involves creating classes that are made up of one or more objects of other classes as an integral part of their structure. The lifecycles of these 'part' objects are tightly coupled to the lifecycle of the 'whole' object. When the whole object is created, the part objects are created. When the whole object is destroyed, so are the part objects.
For example, consider a House
class that contains Room
objects. Each Room
is a part of the House
. The rooms don’t exist as separate entities independent of the house. If you demolish the house (delete the House
object), the rooms (the Room
objects) also cease to exist.
Key points about composition:
Strong Relationship: The part objects are dependent on the whole. They typically don’t make sense to exist on their own.
Lifecycle Management: The whole object manages the lifecycle of its parts. Creating or destroying the whole object will also create or destroy the part objects.
Single Ownership: Each part belongs to only one whole object at a time.
Composition is a strong form of association that represents a very tight coupling between different objects. It's used to model a relationship where the whole is made up of its parts, and these parts are so closely associated with the whole that they do not have an independent existence.
Characteristics of Composition
Strong Ownership: When an object of the composite class is destroyed, the objects of the component class that it holds should also be destroyed.
Single Context: The component objects are part of a single composite object and don't have an independent existence outside this context.
Encapsulation: The component objects are often hidden from the outside world and can be accessed and manipulated only through methods provided by the composite class.
Example
Let's consider a Car
class and an Engine
class. A car has an engine, and the engine can't exist without the car. If the car is destroyed, the engine should be destroyed too. This is a strong "has-a" relationship.
Here's a simple Java example to illustrate composition:
class Engine {
void start() {
System.out.println("Engine started");
}
void stop() {
System.out.println("Engine stopped");
}
}
class Car {
// Composition: Car "has-a" Engine
private Engine engine;
public Car() {
// Initializing the engine within the constructor
this.engine = new Engine();
}
void start() {
engine.start(); // Delegate the start behavior to the engine object
System.out.println("Car started");
}
void stop() {
engine.stop(); // Delegate the stop behavior to the engine object
System.out.println("Car stopped");
}
}
To use this setup:
public class Main {
public static void main(String[] args) {
Car car = new Car(); // Car and its engine are created here
car.start();
car.stop();
}
}
When you create a new Car
object, a new Engine
object gets created within it, and this relationship lasts for the life of the Car
object. If the Car
object gets destroyed, the Engine
object will also be eligible for garbage collection.
Benefits of Composition
Flexibility: It's easier to change the behavior of composite classes by replacing or modifying components.
Reusability: Component classes can be reused in different contexts and composite classes.
Simplicity: Breaking down complex systems into simpler, well-defined components can make the system easier to understand and maintain.
By using composition, you can build complex systems from simple components, making your code more modular, maintainable, and flexible.
COSC-1437 / ITSE-2457 Computer Science Dept. - Author: Dr. Kevin Roark