合成复用原则的核心为在设计类的复用时,要尽量先使用组合或者聚合的方式进行设计,尽量少的使用继承。合成复用原则与里式替换原则是互为补充的。合成复用原则提倡的是尽量不适用继承,如果使用继承,则要遵守里式替换原则。
特点:维持了类的封装性。
类之间的耦合性降低。
复用的灵活性提高,通过协议可以动态修改的引入实体的行为。
现在有这样的一个场景,有一个Teacher教师类,下面有数学老师(MathTeacher)和自然老师(NatureTeacher)的子类
class Teacher {
var name : String
init(name : String) {
self.name = name
}
func teach() {
print("教师正在讲课")
}
}
class MathTeacher : Teacher{
//重写了父类的teach方法
override func teach() {
print("教师\(self.name)教授数学")
}
}
class NatureTeacher : Teacher{
//重写了父类的teach方法
override func teach() {
print("教师\(self.name)教授自然")
}
}
let jack = MathTeacher(name: "Jack")
let lucy = NatureTeacher(name: "Lucy")
jack.teach()
lucy.teach()
我们可以看到数学老师(MathTeacher)和自然老师(NatureTeacher)都重写了父类的方法
func teach() {
print("教师正在讲课")
}
显然违背了里式替换原则。
如果我们采用合成复用原则进行重构,我们可以摒弃继承的方式进行教师的分类。
新定义科目(Subject)类
class Subject {
//教师要绑定科目
var name : String //科目的名字
init(name : String) {
self.name = name
}
}
通过与教师类绑定替换了原来继承的方式来达到合成复用的目的
class Teacher {
var name : String
//教师要绑定科目
var subject : Subject!
init(name : String ,subject : String) {
self.name = name
self.subject = Subject(name: subject)
}
func teach() {
print("教师\(self.name)正在教\(self.subject.name)课")
}
}
//通过定义科目类
class Subject {
//教师要绑定科目
var name : String //科目的名字
init(name : String) {
self.name = name
}
}
//使用的时候
let jack = Teacher(name: "Jack", subject: "数学")
let lucy = Teacher(name: "Lucy", subject: "自然")
jack.teach()
lucy.teach()
这种方式可以有效地去除掉继承带来的高耦合。代码量比原来继承的方式有略微的减少,当我们要想新增科目可以直接增加,这样代码的复用性可以大大的提高,类相对的独立。
7种设计模式的总结:
1.开闭原则是核心原则,其要求我们在设计软件时保持扩展的开放性与修改的封闭性。
2.里式替换原则要求在继承的时候,子类不能破坏父类的实现(即不能重写父类的方法)。
3.单一职责原则要求类的功能要单一。
4.接口隔离原则要求接口的设计要精简。
5.依赖倒置原则要求要面向抽象编程,即为面向接口编程。
6.迪米特原则通过中介类提供了一种降低系统耦合性的方式。
7.合成复用原则要求在组织类的关系时,要慎用继承关系。
网友评论