合成复用原则
也被称为组合复用原则或聚合复用原则。
合成复用原则提倡尽量使用组合或者聚合等关联关系来实现代码复用,而不是通过继承关系来复用代码。组合是一种强的 “拥有” 关系,体现了严格的部分和整体的关系,部分和整体的生命周期一样;聚合是一种弱的 “拥有” 关系,体现的是整体与部分的关系,部分可以脱离整体而单独存在。
通常类的复用分为两类:合成复用和继承复用。
继承复用虽然有简单和易实现的优点,但它也存在以下缺点:
1.继承复用破坏了类的封装性。因为继承会将父类的实现细节暴露给子类,父类对子类是透明的,所以这种复用又称为“白箱’复用。
2.子类与父类的耦合度高。父类的实现的任何改变都会导致子类的实现发生变化,这不利于类的扩展与维护。
3.它限制了复用的灵活性。从父类继承而来·的实现是静态的,在编译时已经定义,所以在运行时,不可能发生变化。
采用组合或聚合复用时,可以将已有对象纳入新对象中,使其成为新对象的一部分,新对象可以调用已有对象的功能,它有以下优点:
1.灵活性更高:继承是一种静态的复用方式,子类与父类之间的关系在编译时就已经确定,不够灵活。而组合和聚合是在运行时动态地建立对象之间的关系,更具灵活性。例如,在一个图形绘制系统中,有 “图形” 类和 “颜色” 类,如果使用继承,每个具体图形类(如圆形、矩形)都需要继承颜色相关的属性和方法,当需要改变颜色的实现方式时,所有子类都可能受到影响。而使用组合,将 “颜色” 对象作为 “图形” 对象的一个成员变量,每个图形对象可以在运行时动态地设置自己的颜色,更加灵活。
2.避免类层次结构的复杂性:过度使用继承会导致类层次结构变得复杂,难以理解和维护。如果一个类继承了多个父类,或者继承层次过深,代码的可读性和可维护性都会降低。而组合和聚合可以将不同的功能模块组合在一起,每个模块相对独立,降低了系统的复杂度。
3.可维护性好:当被复用的模块发生变化时,由于组合和聚合关系中,对象之间是相对独立的,这种变化对其他模块的影响较小。而在继承关系中,父类的修改可能会导致子类的行为发生变化,需要对子类进行相应的修改,增加了维护成本。
案例:图形有各种形状,我们给其中部分涂上阴影,如果使用继承复用,会产生很多子类,如果又有新的形状,又需要定义新的类,而如果将继承复用改为聚合复用,会简单很多。以下是案例示例
//定义一个图形
public class Shape {public void draw(){System.out.println("绘制图形");}
}//定义圆形继承Shape
public class Circle extends Shape{@Overridepublic void draw() {System.out.println("绘制圆形");}
}//定义矩形,继承Shape
public class Rectangle extends Shape{@Overridepublic void draw() {System.out.println("绘制矩形");}
}
//添加阴影效果
class ShadowDecorator {private Shape shape;public ShadowDecorator(Shape shape) {this.shape = shape;}public void draw() {shape.draw();System.out.println("添加阴影效果");}
}
public class Main {public static void main(String[] args) {Shape circle = new Circle();ShadowDecorator circleWithShadow = new ShadowDecorator(circle);Shape rectangle = new Rectangle();ShadowDecorator rectangleWithShadow = new ShadowDecorator(rectangle);circle.draw();circleWithShadow.draw();rectangle.draw();rectangleWithShadow.draw();}
}