1 介绍
合成复用原则(Composite Reuse Principle,CRP),又称组合/聚合复用原则(Composition/Aggregate Reuse Principle,CARP)。该原则强调在软件设计中优先使用组合或聚合关系来实现复用,其次考虑继承关系。
合成复用原则的关键在于理解"组合"和"聚合"的概念。组合指的是一个对象完全支配其组成部分,而聚合则表示一种较弱的“拥有”关系。例如,大雁与翅膀之间是合成关系,因为翅膀是大雁不可分割的一部分;而大雁与雁群之间则是聚合关系,因为每只大雁都是雁群的一部分,但雁群可以有多只大雁。
2 重要性
从多个角度分析,合成复用原则之所以重要,原因在于以下几个方面:
封装性:通过组合或聚合复用,新对象不需要了解成分对象的内部实现细节,保持了良好的封装性,这种复用方式被称为“黑箱”复用。
耦合度:合成复用原则降低了新旧类之间的耦合度,使得新对象对成分对象的依赖减少,有利于代码的维护和扩展。
灵活性:利用组合或聚合关系进行复用,可以在运行时动态地进行,提高了系统的灵活性。
3 核心思想
- 找出应用中可能需要变化之处,把它们独立出来,不要和那些不需要变化的代码混在一起。
- 针对接口编程,而不是针对实现编程。
- 为了交互对象之间的松耦合设计而努力
4 例子
interface Shape {
void draw();
}
class Circle implements Shape {
@Override
public void draw() {
System.out.println("Drawing a circle");
}
}
class Square implements Shape {
@Override
public void draw() {
System.out.println("Drawing a square");
}
}
class ShapeDrawer {
private Shape shape;
public ShapeDrawer(Shape shape) {
this.shape = shape;
}
public void drawShape() {
shape.draw();
}
}
public class Main {
public static void main(String[] args) {
Shape circle = new Circle();
Shape square = new Square();
ShapeDrawer drawer1 = new ShapeDrawer(circle);
ShapeDrawer drawer2 = new ShapeDrawer(square);
drawer1.drawShape(); // Output: Drawing a circle
drawer2.drawShape(); // Output: Drawing a square
}
}
5 优缺点
5.1 优点
封装性: 采用组合/聚合的方式可以隐藏内部实现细节,只暴露必要的接口给外部,这有助于维护良好的封装性。
低耦合性: 通过组合/聚合,类之间的依赖关系降低,每个类都更加独立,修改一个类的实现不会影响到其他类。
高内聚性: 相关的功能被集中到同一个类中,使得该类的职责明确,提高了内聚性。
灵活性: 组合/聚合提供了更大的灵活性,可以在运行时动态地组合对象,增加了系统的适应性。
易于测试: 由于类之间的低耦合性,可以更容易地对各个类进行独立测试。
易于扩展: 新的功能可以通过增加新的组件来实现,而不需要修改现有的代码,符合开闭原则。
5.2 缺点
可能增加系统的复杂性: 为了实现复用,可能会引入更多的小组件,这有可能增加系统的复杂性。
性能考虑: 在某些情况下,过多的组合层次可能会影响性能。
管理难度: 大量的组合/聚合关系可能会增加系统的管理难度,特别是在设计初期没有良好规划的情况下。
6 总结
合成复用原则是面向对象设计中实现复用的重要手段,它鼓励开发者优先使用组合/聚合关系来构建软件系统。通过这种方式,可以提高代码的可维护性、可扩展性和可测试性,同时也能更好地应对需求变化。然而,开发者在应用这一原则时也需要注意其可能带来的复杂性和性能问题,合理地平衡设计的简洁性和灵活性。在现代软件开发中,合成复用原则与其它设计原则如单一职责原则、依赖倒置原则等结合使用,可以更有效地指导高质量的软件设计。