在子类型中使用额外的构造函数参数违反了 LSP 原则
Violation of the LSP-principle using extra constructor parameters in subtypes
当我注意到 this answer 时,我一直在阅读里氏替换原则。它有一个 Circle
和一个 ColoredCircle
类型,其中 ColoredCircle
的构造函数需要一个额外的参数; color
.
class Circle:
radius: int
def __init__(self, radius: int) -> None:
self.radius = radius
class ColoredCircle(Circle):
radius: int
color: str
def __init__(self, radius: int, color: str) -> None:
super().__init__(radius)
self.color = color
这是否违反了以下要求之一? (taken from this answer)。在 ColoredCircle
的情况下,唯一的其他选项是 public 变量或 set_color
方法。
Pre-conditions cannot be strengthened: Assume your base class works
with a member int. Now your sub-type requires that int to be positive.
This is strengthened pre-conditions, and now any code that worked
perfectly fine before with negative ints is broken.
如果我在这里搜索的方向有误,请告诉我。另外,如果一个子类型有更多的参数要处理,通常如何管理这些参数,新的抽象总是 nessacery 吗?
Doesn't this violate one of the requirements below?
这取决于语言;但至少在 Java 中,构造函数不是继承的,因此它们的签名不受管理继承的 LSP 的约束。
子类型最适合修改(超类型的)行为。这称为多态性,子类型做得很好(当遵循 LSP 时)。子类型在代码重用方面表现不佳,例如共享变量。这就是著名原则 prefer composition over inheritance.
背后的思想
当 class X
具有构造函数时,构造函数不是 X
类型对象的方法。由于它不是 X
类型对象的方法,因此它也不必作为派生类型对象的方法存在——它与 LSP 无关。
Liskov 替换原则的目的是类型及其子类型应该是可替换的,这反过来又允许解耦。消费者不必知道对象的实现,只需要知道其声明的类型。如果 class 通过调用其构造函数创建自己的依赖项,则它会耦合到该特定类型。在这种情况下,LSP 变得无关紧要。没有办法替换另一种类型,所以类型是否可替换并不重要。
换句话说 - 创建另一个 class 实例的 class 通常无法从 LSP 中受益,因为它主要排除了用一种类型替换另一种类型的可能性。如果它将该对象传递给其他以创建它以外的方式与其交互的方法,那就是我们从 LSP 中受益的地方。
基于这个推理,我会说不同的构造函数不会违反 Liskov 替换原则的意图。
在许多语言中,我们使用依赖注入来将 classes 从依赖结构中分离出来。这意味着消费者处理类型 除了 的构造函数的每个方面。构造函数不在等式中,子类型可以(或应该)替代它们继承的类型。
当我注意到 this answer 时,我一直在阅读里氏替换原则。它有一个 Circle
和一个 ColoredCircle
类型,其中 ColoredCircle
的构造函数需要一个额外的参数; color
.
class Circle:
radius: int
def __init__(self, radius: int) -> None:
self.radius = radius
class ColoredCircle(Circle):
radius: int
color: str
def __init__(self, radius: int, color: str) -> None:
super().__init__(radius)
self.color = color
这是否违反了以下要求之一? (taken from this answer)。在 ColoredCircle
的情况下,唯一的其他选项是 public 变量或 set_color
方法。
Pre-conditions cannot be strengthened: Assume your base class works with a member int. Now your sub-type requires that int to be positive. This is strengthened pre-conditions, and now any code that worked perfectly fine before with negative ints is broken.
如果我在这里搜索的方向有误,请告诉我。另外,如果一个子类型有更多的参数要处理,通常如何管理这些参数,新的抽象总是 nessacery 吗?
Doesn't this violate one of the requirements below?
这取决于语言;但至少在 Java 中,构造函数不是继承的,因此它们的签名不受管理继承的 LSP 的约束。
子类型最适合修改(超类型的)行为。这称为多态性,子类型做得很好(当遵循 LSP 时)。子类型在代码重用方面表现不佳,例如共享变量。这就是著名原则 prefer composition over inheritance.
背后的思想当 class X
具有构造函数时,构造函数不是 X
类型对象的方法。由于它不是 X
类型对象的方法,因此它也不必作为派生类型对象的方法存在——它与 LSP 无关。
Liskov 替换原则的目的是类型及其子类型应该是可替换的,这反过来又允许解耦。消费者不必知道对象的实现,只需要知道其声明的类型。如果 class 通过调用其构造函数创建自己的依赖项,则它会耦合到该特定类型。在这种情况下,LSP 变得无关紧要。没有办法替换另一种类型,所以类型是否可替换并不重要。
换句话说 - 创建另一个 class 实例的 class 通常无法从 LSP 中受益,因为它主要排除了用一种类型替换另一种类型的可能性。如果它将该对象传递给其他以创建它以外的方式与其交互的方法,那就是我们从 LSP 中受益的地方。
基于这个推理,我会说不同的构造函数不会违反 Liskov 替换原则的意图。
在许多语言中,我们使用依赖注入来将 classes 从依赖结构中分离出来。这意味着消费者处理类型 除了 的构造函数的每个方面。构造函数不在等式中,子类型可以(或应该)替代它们继承的类型。