“针对接口编程,不要针对实现编程”就是依赖倒转原则的最好体现:接口(也可以是抽象类)就是一种抽象,只要不修改接口声明,大家可以放心大胆调用,至于接口的内部实现则无需关心,可以随便重构。这里,接口就是抽象,而接口的实现就是细节
抽象指的是委托/协议,细节就是具体的实现类,使用接口或者抽象类的目的是制定好规范和契约,而不去涉及任何具体的操作,把展现细节的任务交给它们的实现类去完成
代码结构清晰,维护容易
类A直接依赖类B,假如需要将类A改为依赖类C,则必须通过修改类A的代码来达成。这种场景下,类A一般是高层模块,负责复杂的业务逻辑;类B和类C是低层模块,负责基本的原子操作;假如修改类A,会给程序带来不必要的风险
遵循依赖倒置原则,将类A修改为依赖接口I,类B和类C各自实现接口I,类A通过接口I间接与类B或者类C发生联系,则会大大降低修改类A的几率
需求V1:类SalaryManage(类似上面说的类A)负责工资的管理;Staff(类似上面说的类B)是职员类,现在要通过SalaryManage类来给职员发放工资了
class Staff{
var name:String
init(name:String) {
self.name = name
}
func calculateSalary() {
print("\(name)的工资是100")
}
}
class SalaryManage{
func calculateSalary(stasff:Staff) {
stasff.calculateSalary()
}
}
let salary = SalaryManage()
let staff = Staff.init(name: "职员")
salary.calculateSalary(stasff: staff) //职员的工资是100
需求V2:现在假设需要给经理发工资,发现工资管理类SalaryManage没法直接完成这个功能,需要我们添加新的方法,才能完成,那么只能去修改SalaryManage类来满足业务的需求。产生这种现象的原因就是SalaryManage与Staff之间的耦合性太高了,必须降低它们之间的耦合度才行。因此我们引入一个委托EmployeeProtocol,它提供一个发放工资的方法定义
protocol EmployeeProtocol{
func calculateSalary()
}
class SalaryManage{
func calculateSalary(employee:EmployeeProtocol) {
employee.calculateSalary()
}
}
class Staff:EmployeeProtocol{
var name:String
init(name:String) {
self.name = name
}
func calculateSalary() {
print("\(name)的工资是100")
}
}
class Manager:EmployeeProtocol{
var name:String
init(name:String) {
self.name = name
}
func calculateSalary() {
print("\(name)的工资是1000")
}
}
let salary = SalaryManage()
let staff = Staff.init(name: "职员")
let manager = Manager.init(name: "经理")
salary.calculateSalary(employee: staff) // 职员的工资是100
salary.calculateSalary(employee: manager) // 经理的工资是1000
采用依赖倒置原则给多人并行开发带来了极大的便利,比如在上面的例子中,刚开始SalaryManage类与Staff类直接耦合时,SalaryManage类必须等Staff类编码完成后才可以进行编码和测试,因为SalaryManage类依赖于Staff类。按照依赖倒置原则修改后,则可以同时开工,互不影响,因为SalaryManage与Staff类一点关系也没有,只依赖于协议EmployeeProtocol。参与协作开发的人越多、项目越庞大,采用依赖导致原则的意义就越重大