合成复用原则
合成复用原则是指:尽量先使用组合或者聚合等关联关系来实现,其次才考虑使用继承关系来实现。
通常类的复用分为继承复用和合成复用两种。
继承复用里然有简单和易实现的优点,但它也存在以下缺点:
- 继承复用破坏了类的封装性。因为继承会将父类的实现细节暴露给子类,父类对子类是透明的,所以这种复用又称为白箱 复用。
- 子类与父类的男合度高。父类的实现的任何改变都会导致子类的实现发生变化,这不利于类的扩展与维护。
- 它限制了复用的灵活性。从父类继承而来的实现是静态的,在编泽时已经定义,所以在运行时不可能发生变化。
采用组合或聚合复用时,可以将已有对象纳入新对象中,使之成为新对象的一部分,新对象可以调用已有对象的功能,它有以下优点:
- 它维持了类的封装性。因为成分对象的内部细节是新对象看不见的,所以这种复用又称为黑箱复用。
- 对象间的耦合度低。可以在类的成员位置声明抽象。
- 复用的灵活性高。这种复用可以在运行时动态进行,新对象可以动态地引用与成分对象类型相同的对象。
【例】汽车分类管理程序
汽车按、动力源〞划分可分为汽油汽车、电动汽车等;按、颜色〞划分可分为白色汽车、黑色汽车和红色汽车等。如果同时考虑这两种分类,其组合就很多。
采用继承方法的话就会有白色电动汽车,白色汽油汽车,黑色电动汽车,黑色汽油汽车,如果后续增加了更多的能源或者颜色,就需要再定义新的类。
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(),"电动汽车")
}
}
运行结果
我们定义Color接口、还有一个Car的类,Car类中聚合了Colour颜色对象,此时拥有了一个光能汽车类型 我们只需要定义一个光能汽车的类,无需再定义白色光能汽车类、黑色光能汽车类。
感谢黑马程序员课程