我们在books
对象中有一本书的列表。我们如何从中删除一本书,假设我们知道它的ID?我们可以使用books.removeById(42)
。另外,我们可以使用books.findById(42)
来找到它,然后调用b.remove()
。我们应该选择哪个选项,为什么?第二个选择是更好的。不仅因为它更面向对象,而且还有几个实际优势。
如果我们想要扩展删除算法怎么办?例如,假设我们希望在删除书籍时打印一条日志消息。
如果我们遵循开闭原则,我们应该避免修改现有的Book
或Books
类。相反,我们希望扩展或装饰它们。如果我们想避免实现继承,装饰器是理想的选择。
如果我们使用removeById()
,我们必须装饰books
对象。如果我们使用remove()
,我们可以装饰通过findById()
检索到的单个书籍。后一种方法可能更具内聚性,因为其装饰对象可能更小和更专注:
Handling Missing or Non-Deletable Books
如果找不到书籍或无法删除该书籍怎么办?removeById()
方法并不很好地支持Null Object模式。它强迫我们抛出异常—或者更糟糕的是返回false
,这违背了CQRS原则。
另一方面,返回一个对象,即使是一个null或假对象,提供了更多的灵活的错误处理。例如,我们可以安全地访问title()
,知道书籍已成功找到—或者捕获并带有更多上下文重新引发异常:
Decoupling Retrieval and Deletion
如果对象的检索和删除在代码中相隔较远会怎样呢?
如果 books
知道如何找到,而 book
知道如何删除,我们可以很好地将责任分开。这也允许书籍是不可变的,并封装自己的 ID,减少内部数据的泄漏:
一旦ID被findById()
包裹在书中,它就再也不必泄漏出来了。这减少了暴露给不需要的代码部分的裸数据量。
可见数据越少,设计就越好—至少从面向对象编程的角度来看。
因此,使用findById()
后跟remove()
更全面地拥抱面向对象的原则。它允许更清晰的扩展、更好的错误处理和更紧密的封装。
Translated by ChatGPT gpt-3.5-turbo/42 on 2025-06-22 at 14:22