定义:要求在软件复用时,尽量先使用组合或者聚合等关联关系来实现,其次才考虑使用继承关系来实现。
虽然继承也能提高代码的复用性,但存在很多问题,下面会说到。
如果要使用继承关系,则必须严格遵循里氏替换原则。合成复用原则同里氏替换原则相辅相成,两者都是开闭原则的具体实现规范。
“里氏替换原则”定义回顾: 继承必须确保超类所拥有的性质在子类中仍然成立。(任何基类可以出现的地方,子类一定可以出现)
“里氏替换原则”经典案例:“正方形不是长方形”。
分类:合成复用原则通常分为“继承复用”和“合成复用”两种。
继承复用:通过继承来实现代码的复用性。
合成复用:通过组合或聚合实现代码的复用性。
两种复用方式的优缺点:
继承复用虽然有简单和易实现的优点,但它也存在以下缺点:
1.继承复用破坏了类的封装性。因为继承会将父类的实现细节暴露给子类,父类对子类是透明的(子类可以直接继承父类的功能,也可以覆盖掉这些功能),所以这种复用又称为"白箱"复用。
2.子类与父类的耦合度高(继承本身就比聚合、组合的耦合度高)。父类的实现的任何改变都会导致子类的实现发生变化,这不利于类的扩展与维护。
3.它限制了复用的灵活性。从父类继承而来的实现是静态的,在编译时已经定义,所以在运行时不可能发生变化(在运行时不能解除子类对父类的继承)。
采用组合或聚合复用时,可以将已有对象纳入新对象中,使之成为新对象的一部分,新对象可以调用已有对象的功能,它有以下优点:
1.它维持了类的封装性。因为成分对象(成员对象)的内部细节是新对象看不见的,所以这种复用又称为"黑箱”复用。
2.对象间的耦合度低。可以在类的成员位置声明抽象(声明成抽象父类或父接口,可动态传递子类对象)。
3.复用的灵活性高。这种复用可以在运行时动态进行,新对象可以动态地引用与成分对象类型相同的对象。(给成员变量进行赋值,可在运行时对其进行赋值)
实现方法:将已有对象纳入新对象中,作为新对象的一部分,新对象从而就可以调用已有对象的功能。
应用:“汽车分类管理程序”
分析:汽车按“动力源”划分可分为汽油汽车、电动汽车;按“颜色”划分可以分为白色汽车、黑色汽车和红色汽车等。
如果考虑使用继承复用来实现此案例,那么,顶层父类就是汽车类(Car);根据“动力源”分类,继承它的子类有两个:汽油汽车(PetolCar)和电动汽车(ElectricCar);根据“颜色”分类,这两个子类又各自有自己的子类:红色汽油汽车(RedPetolCar)、白色汽油汽车(WhitePetrolCar),红色电动汽车(RedElectricCar)、白色电动汽车(WhiteElectricCar)。
根据以上类图,如果现在有新的动力源(光能汽车)或者新的颜色,那么添加的子类就特别多。(下图是增加光能汽车后的类图)
改进方法:改用聚合复用。(类图如下)
根据以上类图,如果现在有新的动力源(光能汽车)或者新的颜色,只需定义新的光能汽车类(LightEneryCar),使其继承Car类,而不需要定义光能汽车的子类(因为在Car类中已经聚合Color,在new具体汽车类时可传递具体的颜色子类对象)(下图是增加光能汽车后的类图)
{{ cmt.username }}
{{ cmt.content }}
{{ cmt.commentDate | formatDate('YYYY.MM.DD hh:mm') }}