【问题标题】:Violation of Liskov Substitution Principle in SharedFolderSharedFolder 中违反 Liskov 替换原则
【发布时间】:2016-08-03 07:35:40
【问题描述】:

目前的设计是

  1. SharedFolderFolder 的子类。
  2. SharedFile 是具有远程资源 URL 的 File 的子类。
  3. Folderadd 方法中接受 File
  4. SharedFolder 仅接受 SharedFile 但不接受非共享 File
  5. File 可以通过 add 移动到另一个 Folder
  6. SharedFolderFolder 中浏览文件的 UI 基本相同。

SharedFile 中的 add 违反了 LSP。如何在允许某些 UI 代码重用的同时重新组织对象结构?

【问题讨论】:

  • 您可以定义 add 方法以不通过合同保证在所有情况下都可以添加。这样就不会出现替换失败。
  • @usr,你是说文档本身就可以满足LSP?在这种情况下,即使是臭名昭著的 Iterator.remove() 方法也满足 LSP。
  • 静态输入只是一种以机器可读的方式添加一些文档的方法。接口契约是任意的。它是你定义的任何东西。不要纠结于语法或语言问题。
  • 作为一个具体的解决方案,您可以添加此方法:bool TryAdd(File f) 并允许文件夹以任何原因拒绝项目。这样你就可以通过告诉用户“这个文件不能放在这里”来在 UI 中显示它。投掷也可以。异常只是返回某些东西的另一种方式。
  • 我同意@usr,并不是所有的规则和不变量都必须通过类型检查来强制执行。我会在这里抛出一个异常或返回 AddResult 而不是 bool 这不会真正让客户知道出了什么问题。

标签: oop inheritance solid-principles liskov-substitution-principle


【解决方案1】:

您可以将Folder 泛化为Folder<T extends File>,使用add(T),并拥有SharedFolder extends Folder<SharedFile>

这样,SharedFolder 只能替换另一个 Folder<SharedFile>,而不是任何其他类型的 Folder<File>

(如果您的语言允许。这在 Java 中是可能的)

【讨论】:

  • 大概他需要能够将任何文件夹类型存储在一个变量中。然后,通用约束信息丢失,LSP 违规又回来了。
  • 如果您使用任何文件夹类型,则不能在该文件夹中存储任何文件类型。你不能只是摆脱一般约束。
【解决方案2】:

您的问题有很多可能的答案。这里有两个:

  • Folder 基类中删除add 方法,只让它公开File 元素的(只读)集合。
  • 删除SharedFolderFolder 之间的“是”关系。换句话说,不要让SharedFolder 继承自Folder。相反,您可以让 SharedFolder 成为某种元数据类,其中包含 Folder(组合优于继承)。

【讨论】:

  • 第一个答案如何满足LSP?集合需要是不可变的吗?否则,有问题的 add() 方法只是移动到集合中。
  • @jaco0646 这解决了问题,因为基类的消费者将无法调用add 并插入与派生类协定不兼容的项目。
  • ...但大概消费者仍然可以调用getCollection().add(),这在与原始add()相同的情况下会失败。
  • @jaco0646:啊,是的,我忘了说该集合应该是从外部只读的。
  • 如果使用设计2,如何重用代码?通常,组合需要抽象接口。
猜你喜欢
  • 1970-01-01
  • 2015-01-01
  • 1970-01-01
  • 2011-09-09
  • 2012-01-12
  • 1970-01-01
  • 1970-01-01
  • 2018-04-27
  • 2012-03-16
相关资源
最近更新 更多