我有一个模型抽象类,它声明了一个项目列表。抽象有两个抽象类。一种是您可以将新项目添加到列表中,另一种是根本不使用该列表,而是遵循模型抽象类的其他行为。
我声明了两种从列表中添加和删除项目的方法。显然,每当我想使用这些方法时,我都需要用它的子类来转换我的模型抽象。
在这种情况下我可以违反LSP(Liskov 替换原则)吗?或者有没有办法解决这个问题?
我有一个模型抽象类,它声明了一个项目列表。抽象有两个抽象类。一种是您可以将新项目添加到列表中,另一种是根本不使用该列表,而是遵循模型抽象类的其他行为。
我声明了两种从列表中添加和删除项目的方法。显然,每当我想使用这些方法时,我都需要用它的子类来转换我的模型抽象。
在这种情况下我可以违反LSP(Liskov 替换原则)吗?或者有没有办法解决这个问题?
我认为你会违反 LSP。
从LSP 的 Wikipedia 页面(始终是您的朋友;):
“更正式地说,里氏替换原则 (LSP) 是子类型关系的特定定义,称为(强)行为子类型”
“行为子类型是比类型论中定义的函数的典型子类型更强大的概念,它仅依赖于参数类型的逆变和返回类型的协变。行为子类型通常是微不足道的不可判定的”
看起来与您的情况相似:
“一个违反 LSP 的典型例子是从 Rectangle 类派生的 Square 类,假设宽度和高度都存在 getter 和 setter 方法。Square 类总是假设宽度与高度相等。如果使用 Square 对象在期望 Rectangle 的上下文中,可能会发生意外的行为,因为 Square 的尺寸不能(或者不应该)独立修改。这个问题不容易解决:如果我们可以修改 Square 类中的 setter 方法,以便它们保留 Square 不变量(即,保持维度相等),那么这些方法将削弱(违反)Rectangle setter 的后置条件,即维度可以独立修改。违反 LSP 的情况,比如这个,可能会也可能不会在实践中成为问题”
我了解 LSP,但这里可能是问题解决了 java 具有单继承和多接口的设计原因。
一个类只能扩展另一个类。在 C++ 中,情况并非如此,超类中可能存在冲突的名称。多重继承也给出了一些理论上的类型问题。
所以你必须把一个方面变成一个接口,并从实现一个或多个接口的抽象类扩展。
当 Square 从 Rectangle 扩展并实现 WidthEqualsHeight 时,LSP 成立。
从来没有学过 LSP 但我不好说
必须强制转换始终是糟糕(不太理想)OO 设计的标志。
如果你想要一个模型,你也可以设置东西,然后将它声明为正确的模型
Java 集合 API 也是如此
Collection coll = new ArrayList();
((List) coll).set(3,"sdf");
是可以工作但写得不好的代码吗
本来应该是
List coll = new ArrayList();
coll.set(3,"sdf");
使用您想要的特定类型