liskov替换原则和接口隔离原则的区别
The difference between liskov substitution principle and interface segregation principle
里氏代换原则(LSP)和接口隔离原则(ISP)有核心区别吗?最终,两者都保证设计具有通用功能的界面,并在您有特殊用途的功能时引入新界面。
LSP:子类型必须遵守它承诺的契约。
ISP:调用者不应该依赖比它需要更多的基类型接口。
适合的地方:如果您应用 ISP,则您只使用接收器完整接口的一部分。但根据 LSP,接收方仍必须遵守该切片。
如果申请ISP失败,就有可能违反LSP。因为“这个方法无关紧要,实际上不会被调用。”
它们都是 SOLID 原则
- LSP(Liskov 替换):此原则要求您确保所有子 class 具有与父 class 相同的行为。
例如:如果你有一个
Device
class 并且它有函数 callBaba()
可以得到你父亲的 phone 号码然后给他打电话,所以你必须确保 callBaba()
方法在 Device
的所有子 class 中做同样的工作。如果 Device
的任何子 classes 在 callBaba()
中有其他行为,这意味着你破坏了 LSP
Example of code that breaks Liskov Principle.
class Device {
func callBaba() {
print("I will find your father and I will call him")
}
}
class Calculator: Device {
override func callBaba() {
print("Sorry, I don't have this functionality ")
}
}
The Solution
interface CanCall {
func callBaba()
}
class Device {
// all basic shared functions here.
}
class Calculator: Device {
// all functions that calculator can do + Device
}
class SmartPhone: Device implements CanCall {
// all smartphone stuff
func callBaba() {
print("I will find your father and I will call him")
}
}
- ISP(Interface Segregation):要求你为不同的职责创建不同的接口,换句话说,不要将不相关的行为分组在一个接口中,
如果你破坏了 ISP
你已经有了一个有很多职责的接口,实现者不需要所有这些东西
this breaks ISP principle because it has two different
responsibilities
protocol Animal {
func fly()
func eat()
}
The Solution
protocol Flyable {
func fly()
}
protocol Feedable {
func eat()
}
LSP 管理 parent 和 child classes 之间的关系(即层次关系)。它告诉您 如何 实施 API。
ISP 管理 parent 和客户端 class 之间的关系(即 producer/consumer 关系)。它告诉您何时 实施API。
考虑一个有一百个方法的接口。一个 child class 可以执行所有 hundred 而不会违反其中任何一个定义的契约,从而满足 Liskov 替换;但很难想象每个客户端都需要所有这些方法,因此几乎肯定会违反接口隔离。
反之,只有一个方法的接口肯定满足接口隔离;但是如果一个实现不遵守那个方法契约,那么 Liskov 替换就被违反了。
另请参阅:LSP vs DIP
里氏代换原则(LSP)和接口隔离原则(ISP)有核心区别吗?最终,两者都保证设计具有通用功能的界面,并在您有特殊用途的功能时引入新界面。
LSP:子类型必须遵守它承诺的契约。
ISP:调用者不应该依赖比它需要更多的基类型接口。
适合的地方:如果您应用 ISP,则您只使用接收器完整接口的一部分。但根据 LSP,接收方仍必须遵守该切片。
如果申请ISP失败,就有可能违反LSP。因为“这个方法无关紧要,实际上不会被调用。”
它们都是 SOLID 原则
- LSP(Liskov 替换):此原则要求您确保所有子 class 具有与父 class 相同的行为。
例如:如果你有一个
Device
class 并且它有函数callBaba()
可以得到你父亲的 phone 号码然后给他打电话,所以你必须确保callBaba()
方法在Device
的所有子 class 中做同样的工作。如果Device
的任何子 classes 在callBaba()
中有其他行为,这意味着你破坏了 LSP
Example of code that breaks Liskov Principle.
class Device {
func callBaba() {
print("I will find your father and I will call him")
}
}
class Calculator: Device {
override func callBaba() {
print("Sorry, I don't have this functionality ")
}
}
The Solution
interface CanCall {
func callBaba()
}
class Device {
// all basic shared functions here.
}
class Calculator: Device {
// all functions that calculator can do + Device
}
class SmartPhone: Device implements CanCall {
// all smartphone stuff
func callBaba() {
print("I will find your father and I will call him")
}
}
- ISP(Interface Segregation):要求你为不同的职责创建不同的接口,换句话说,不要将不相关的行为分组在一个接口中, 如果你破坏了 ISP 你已经有了一个有很多职责的接口,实现者不需要所有这些东西
this breaks ISP principle because it has two different responsibilities
protocol Animal {
func fly()
func eat()
}
The Solution
protocol Flyable {
func fly()
}
protocol Feedable {
func eat()
}
LSP 管理 parent 和 child classes 之间的关系(即层次关系)。它告诉您 如何 实施 API。
ISP 管理 parent 和客户端 class 之间的关系(即 producer/consumer 关系)。它告诉您何时 实施API。
考虑一个有一百个方法的接口。一个 child class 可以执行所有 hundred 而不会违反其中任何一个定义的契约,从而满足 Liskov 替换;但很难想象每个客户端都需要所有这些方法,因此几乎肯定会违反接口隔离。
反之,只有一个方法的接口肯定满足接口隔离;但是如果一个实现不遵守那个方法契约,那么 Liskov 替换就被违反了。
另请参阅:LSP vs DIP