当前位置: 首页 > 面试题库 >

Collections.unmodifiableXXX方法是否违反LSP?

鲍建业
2023-03-14
问题内容

Liskov替换原理是SOLID的原理之一。我已经读过几次这个原理,并试图理解它。

这就是我的所作所为,

此原则与类层次结构之间的强行为契约有关。子类型应该能够被超类型替换而不会违反合同。

我也读过其他文章,对这个问题我有些失落。难道Collections.unmodifiableXXX()方法不违反LSP?

上面链接的文章摘录:

换句话说,当通过对象的基类接口使用对象时,用户仅知道基类的前提条件和后置条件。因此, 派生对象不能期望此类用户遵守比基类所要求的条件强的条件

我为什么会这样呢?

之前

class SomeClass{
      public List<Integer> list(){
           return new ArrayList<Integer>(); //this is dumb but works
      }
}

class SomeClass{
     public List<Integer> list(){
           return Collections.unmodifiableList(new ArrayList<Integer>()); //change in implementation
     }
}

我不能改变SomeClass将来返回不可修改清单的目的。编译将起作用,但是如果客户端以某种方式尝试更改List返回的内容,则它将在运行时失败。

这就是为什么Guava 为集合创建了单独的ImmutableXXX接口吗?

这不是直接违反LSP还是我完全理解错了?


问题答案:

LSP表示每个子类都必须遵守与超类相同的合同。是否Collections.unmodifiableXXX()如此,取决于合同的阅读方式。

Collections.unmodifiableXXX()如果尝试调用任何修改方法,则由返回的对象将引发异常。例如,如果add()被调用,UnsupportedOperationException将抛出。

什么是总合同add()?根据API文档,它是:

确保此集合包含指定的元素(可选操作)。如果此集合由于调用而更改,则返回true。(如果此集合不允许重复并且已经包含指定的元素,则返回false。)

如果这是一份完整的合同,那么无法修改的变体确实不能在所有可以使用收藏的地方使用。但是,该规范仍在继续,并指出:

如果某个集合由于已经包含该元素以外的其他原因拒绝添加该元素,则它必须引发一个异常(而不是返回false)。这保留了不变,即在此调用返回之后,集合始终包含指定的元素。

这明确允许实现具有不将参数添加add到集合中但导致异常的代码。当然,这包括托收客户有义务考虑到(合法)可能性。

因此,行为子类型(或LSP)仍然可以满足。但这表明,如果计划在子类中具有不同的行为,则还必须在顶级类的规范中预见到这种行为。

好的,顺便问一下。



 类似资料:
  • 根据方法<code>java.util.concurrent的约定。未来#取消: 此方法返回后,对 isDone 的后续调用将始终返回 true。 Netty的Future接口扩展了它: 所以Netty应该遵守合同。但事实上Netty没有。您可以运行以下示例代码: 控制台应打印: 真 但实际上它打印: 假 以下方法也违反了合同: 我已经在github上创建了一个问题:问题 但是我仍然想在stack

  • 来自Liskov替代原理-www.blackwasp。co.uk 不符合LSP的一个常见指示是当客户端类检查其依赖项的类型时。这可以通过读取人为描述其类型的对象的属性或通过使用反射来获得类型。通常,根据依赖项的类型,将使用开关语句执行不同的操作。这种额外的复杂性也违反了打开/关闭原则(OCP),因为随着更多子类的引入,客户端类需要修改。 以下技术(使用反射)是否会导致违反LSP? 依赖注入 注:我

  • 我问这个问题更多的是出于好奇,而不是真正关心它,但我一直想知道JavaScript事件系统是否违反了Liskov替换原则(LSP)。 通过调用,我们可以调度任意类型的,该事件可能由注册的处理。 如果我正确理解了LSP,那就意味着不应失败。但是,通常情况并非如此,因为事件侦听器通常会使用专门的子类型的属性。 在不支持泛型的类型化语言中,这种设计基本上需要将对象向下转换为中的预期子类型。 根据我的理解

  • 考虑以下程序: (编译器资源管理器) GCC和Clang的各种版本都可以接受它,但MSVC不能接受它,因为MSVC编译失败,出现错误消息 第一条错误消息向我暗示了ODR违规--但如果这个程序是格式不良的NDR,我需要帮助理解为什么会这样。我已经检查了标准草案中的temp.over.link,但我不相信我对它的解释是正确的。根据我的理解,程序是可以的,因为这些函数模板有不同的签名。 在不太可能的情况

  • 问题内容: 我对单一责任原则感到困惑。 《原则》指出,阶级改变只有一个原因。 我面临的问题是,对方法的任何更改或在执行操作中的任何逻辑更改都会更改类。例如,考虑以下类: 鲍勃叔叔将其描述为 仅由一个人/演员负责更改 。我有以下两个问题: 对于上述阶层,谁是负责变革的演员/人? 饮食,呼吸或行走的逻辑上的任何改变都不会改变人的类吗?难道这并不意味着每种方法都是改变的理由,因为做事的逻辑可能会改变吗?

  • 如果S是T的一个子类型,那么T类型的对象可以被S类型的对象替换。 子类有两种不同的行为(选中与未选中),在某些情况下,除非更改当前代码,否则无法用子类对象有效地替换基类用法,例如,如果编写如下代码: 这是违反吗?,为什么/为什么不?。 资料来源:http://www.oracle.com/technetwork/articles/entarch/effective-exceptions-09234