Fundamentals 11 min read

Understanding the Composite Reuse Principle (CRP): Concepts, Benefits, UML, and Implementation Examples

This article provides a comprehensive explanation of the Composite Reuse Principle (CRP), covering its definition, background, advantages over inheritance, UML representation, practical Java code examples, and guidelines for choosing between composition and inheritance in object‑oriented design.

Mike Chen's Internet Architecture
Mike Chen's Internet Architecture
Mike Chen's Internet Architecture
Understanding the Composite Reuse Principle (CRP): Concepts, Benefits, UML, and Implementation Examples

Composite Reuse Principle (CRP) , also known as the Composition/Aggregation Reuse Principle, advocates using composition or aggregation before inheritance to achieve code reuse.

01. What is the Composite Reuse Principle?

The CRP states that when reusing code, developers should first consider composition or aggregation relationships, and only resort to inheritance if necessary.

02. Origin of the Composite Reuse Principle

Early object‑oriented programming relied heavily on inheritance for reuse, which introduced problems such as tight coupling, complex inheritance hierarchies, exposure of internal implementation (white‑box reuse), and limited flexibility because inheritance is static.

To address these issues, the Composite Reuse Principle was introduced, promoting more elegant code reuse through composition.

Advantages of Composition

Low coupling: components are loosely connected, reducing dependency.

Black‑box reuse: internal details of composed objects remain hidden, preserving encapsulation.

Higher flexibility: composition is not constrained by static inheritance relationships.

Supports the Single Responsibility Principle for each component.

03. Choosing Between Composition and Inheritance

Composition is suitable when requirements change frequently or when a class needs functionality from other classes without inheriting all their members. Inheritance is appropriate for extending existing class behavior, but must obey the Liskov Substitution Principle and the Coad rules.

3.1 Liskov Substitution Principle

Subtypes must be replaceable for their base types without altering expected behavior.

3.2 Coad Rules

Use inheritance only for true "is‑a" relationships; use composition for "has‑a" relationships.

Avoid inheritance when future substitution of subclasses is uncertain.

Subclasses should extend, not replace, parent responsibilities.

Do not inherit from utility classes unless they represent a taxonomy.

04. Implementation Example

Assume a car management program with two classification dimensions: power source (electric, petrol) and color (white, black, red). Using inheritance would require six subclasses, leading to class explosion and violation of the Open/Closed Principle.

Using composition, we define a Color interface with concrete implementations (White, Black, Red) and inject a Color object into the Car class.

Code using inheritance:

public abstract class Car {
abstract void run();
}
public class ElectricCar extends Car {
@Override
void run() {
System.out.println("电动汽车");
}
}
public class PetrolCar extends Car {
@Override
void run() {
System.out.println("汽油汽车");
}
}
public class BlackElectricCar extends ElectricCar {
public void appearance() {
System.out.print("黑色");
super.run();
}
}
... (other color‑specific subclasses) ...
public class Test {
public static void main(String[] args) {
RedElectricCar redElectricCar = new RedElectricCar();
redElectricCar.appearance(); // 红色电动汽车
}
}

Code using composition:

public abstract class Car {
abstract void run();
Color color;
public Color getColor() { return color; }
public void setColor(Color color) { this.color = color; }
}
public interface Color {
void colorKind();
}
public class ElectricCar extends Car {
@Override
void run() { System.out.println("电动汽车"); }
}
public class PetrolCar extends Car {
@Override
void run() { System.out.println("汽油汽车"); }
}
public class White implements Color {
@Override
public void colorKind() { System.out.println("白色"); }
}
public class Black implements Color {
@Override
public void colorKind() { System.out.println("黑色"); }
}
public class Red implements Color {
@Override
public void colorKind() { System.out.println("红色"); }
}
public class Test {
public static void main(String[] args) {
ElectricCar electricCar = new ElectricCar();
White white = new White();
electricCar.setColor(white);
electricCar.getColor().colorKind(); // 白色
electricCar.run(); // 电动汽车
}
}

With composition, only five classes are needed, and adding new colors or power sources requires creating new Color implementations without modifying existing code, thus adhering to the Open/Closed Principle.

Summary

The Composite Reuse Principle encourages using composition over inheritance for code reuse, offering lower coupling, better encapsulation, and greater flexibility; it should be applied after evaluating the Liskov Substitution Principle and Coad rules, and illustrated with Java examples that contrast inheritance‑heavy designs with composition‑based solutions.

Design PatternsJavacode reuseObject-Oriented DesignComposite Reuse PrincipleComposition over Inheritance
Mike Chen's Internet Architecture
Written by

Mike Chen's Internet Architecture

Over ten years of BAT architecture experience, shared generously!

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.