软件设计原则-合成复用原则

253 阅读3分钟

合成复用原则

合成复用原则是指:尽量先使用组合或者聚合等关联关系来实现,其次才考虑使用继承关系来实现。

通常类的复用分为继承复用和合成复用两种。

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

  1. 继承复用破坏了类的封装性。因为继承会将父类的实现细节暴露给子类,父类对子类是透明的,所以这种复用又称为白箱 复用。
  2. 子类与父类的男合度高。父类的实现的任何改变都会导致子类的实现发生变化,这不利于类的扩展与维护。
  3. 它限制了复用的灵活性。从父类继承而来的实现是静态的,在编泽时已经定义,所以在运行时不可能发生变化。

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

  1. 它维持了类的封装性。因为成分对象的内部细节是新对象看不见的,所以这种复用又称为黑箱复用。
  2. 对象间的耦合度低。可以在类的成员位置声明抽象。
  3. 复用的灵活性高。这种复用可以在运行时动态进行,新对象可以动态地引用与成分对象类型相同的对象。

【例】汽车分类管理程序

汽车按、动力源〞划分可分为汽油汽车、电动汽车等;按、颜色〞划分可分为白色汽车、黑色汽车和红色汽车等。如果同时考虑这两种分类,其组合就很多。

采用继承方法的话就会有白色电动汽车,白色汽油汽车,黑色电动汽车,黑色汽油汽车,如果后续增加了更多的能源或者颜色,就需要再定义新的类。

protocol Car{
    func move()
}
class PetrolCar:Car{
    func move() {
        print("汽油汽车")
    }
}
class ElectricCar:Car{
    func move() {
        print("电动汽车")
    }
}
class WhitePetrolCar:PetrolCar{
    override func move() {
        print("白色汽油汽车类")
    }
}
class BlackPetrolCar:PetrolCar{
    override func move() {
        print("黑色汽油汽车类")
    }
}
class WhiteElectricCar:PetrolCar{
    override func move() {
        print("白色电动汽车类")
    }
}
class BlackElectricCar:PetrolCar{
    override func move() {
        print("黑色电动汽车类")
    }
}

改进后 我们试着将继承复用改为聚合复用试一下:

protocol Color{
    func getColor()->String
}
class RedColor:Color{
    func getColor()->String {
        return "红色"
    }
}
class Car{
    var color:Color?
    func move(){
        
    }
}
class PetrolCar:Car{
    override func move(){
        print(color!.getColor(),"汽油汽车")
    }
}
class ElectricCar:Car{
    override func move(){
        print(color!.getColor(),"电动汽车")
    }
}
​

运行结果

image-20220910104536270

我们定义Color接口、还有一个Car的类,Car类中聚合了Colour颜色对象,此时拥有了一个光能汽车类型 我们只需要定义一个光能汽车的类,无需再定义白色光能汽车类、黑色光能汽车类。

感谢黑马程序员课程