Java设计模式-软件设计原则-合成复用原则

岳庆锦

发布于 2022.03.11 00:07 阅读 1808 评论 0

合成复用原则(组合/聚合复用原则)

 定义:要求在软件复用时,尽量先使用组合或者聚合等关联关系来实现,其次考虑使用继承关系来实现。

 虽然继承也能提高代码的复用性,但存在很多问题,下面会说到。

 如果要使用继承关系,则必须严格遵循里氏替换原则合成复用原则同里氏替换原则相辅相成,两者都是开闭原则的具体实现规范。

 “里氏替换原则”定义回顾 继承必须确保超类所拥有的性质在子类中仍然成立。(任何基类可以出现的地方,子类一定可以出现)

 “里氏替换原则”经典案例:“正方形不是长方形”。

 分类:合成复用原则通常分为“继承复用”和“合成复用”两种。

继承复用:通过继承来实现代码的复用性。

合成复用:通过组合或聚合实现代码的复用性。

 两种复用方式的优缺点

 继承复用虽然有简单易实现优点,但它也存在以下缺点

1.继承复用破坏了类的封装性。因为继承会将父类的实现细节暴露给子类,父类对子类是透明的(子类可以直接继承父类的功能,也可以覆盖掉这些功能),所以这种复用又称为"白箱"复用。

2.子类与父类的耦合度高(继承本身就比聚合、组合的耦合度高)。父类的实现的任何改变都会导致子类的实现发生变化,这不利于类的扩展与维护。

3.它限制了复用的灵活性。从父类继承而来的实现是静态的,在编译时已经定义,所以在运行时不可能发生变化(在运行时不能解除子类对父类的继承)。

 采用组合或聚合复用时,可以将已有对象纳入新对象中,使之成为新对象的一部分,新对象可以调用已有对象的功能,它有以下优点:

1.它维持了类的封装性。因为成分对象(成员对象)的内部细节是新对象看不见的,所以这种复用又称为"黑箱”复用。

2.对象间的耦合度低。可以在类的成员位置声明抽象(声明成抽象父类或父接口,可动态传递子类对象)。

3.复用的灵活性高。这种复用可以在运行时动态进行,新对象可以动态地引用与成分对象类型相同的对象。(给成员变量进行赋值,可在运行时对其进行赋值)

 实现方法:将已有对象纳入新对象中,作为新对象的一部分,新对象从而就可以调用已有对象的功能。

 应用:“汽车分类管理程序”

 分析:汽车按“动力源”划分可分为汽油汽车、电动汽车;按“颜色”划分可以分为白色汽车、黑色汽车和红色汽车等。

如果考虑使用继承复用来实现此案例,那么,顶层父类就是汽车类(Car);根据“动力源”分类,继承它的子类有两个:汽油汽车(PetolCar)和电动汽车(ElectricCar);根据“颜色”分类,这两个子类又各自有自己的子类:红色汽油汽车(RedPetolCar)、白色汽油汽车(WhitePetrolCar),红色电动汽车(RedElectricCar)、白色电动汽车(WhiteElectricCar)。

根据以上类图,如果现在有新的动力源(光能汽车)或者新的颜色,那么添加的子类就特别多。(下图是增加光能汽车后的类图)

 改进方法:改用聚合复用。(类图如下)

根据以上类图,如果现在有新的动力源(光能汽车)或者新的颜色,只需定义新的光能汽车类(LightEneryCar),使其继承Car类,而不需要定义光能汽车的子类(因为在Car类中已经聚合Color,在new具体汽车类时可传递具体的颜色子类对象)(下图是增加光能汽车后的类图)