第11章 依靠重新设计
本作品已使用人工智能进行翻译。欢迎您提供反馈和意见:translation-feedback@oreilly.com
总的来说,随着需求的增长,你的设计应该不断发展......1Martin Fowler,《企业应用架构模式》(Addison-Wesley,2002 年)
我们在第 3 章中介绍了 Portfolio 实体。它代表了我们领域中的一个关键概念,因此我们有理由赋予它一些职责。现在,我们的Portfolio 做了太多的工作,这一点显而易见。它的主要任务是作为Money 实体的存储库。不过,它还承担了货币间转换的额外责任。为此,它必须保留汇率表和进行转换的逻辑。这看起来不像是Portfolio 的职责。货币转换在投资组合中的作用就像花生酱在比萨饼上的作用一样大。
我们的软件程序随着我们的需求而成长。值得改进的是我们的设计,并寻找一种比目前实现货币间转换的方式更好的抽象方法。
领域驱动设计(DDD)的一个原则就是不断学习。 当我们学到有关领域的新知识时,我们的设计就会反映出我们所获得的知识。由此产生的设计和软件应能反映出我们对领域的进一步理解。
提示
领域驱动设计是一门得到 TDD 大力支持的学科。埃里克-埃文斯(Eric Evans)的同名著作是这一主题的开山之作。
通过在过去几章中实施货币转换,我们对我们的程序有了新的认识。 它缺少一个关键实体。现实世界中帮助我们兑换货币的机构名称是什么?银行。或货币兑换机构。通常情况下,一个领域会有多个类似的实体,从我们的模型角度来看,这些实体是无法区分的。了解哪些差异是显著的,哪些差异是不重要的,这对有效的领域建模至关重要。
我们将选择Bank 来代表这个缺失的实体。Bank 的职责是什么?首先,它应该掌握汇率。而且它应该能够根据汇率在不同货币之间进行货币兑换。Bank 应该允许非对称汇率,因为现实世界中存在非对称汇率。最后,当由于汇率缺失而无法将一种货币兑换成另一种货币时,Bank 应明确告知我们。(请参阅第 8 章中的"混合货币",其中列出了货币兑换的基本规则)。
作为持有汇率的实体,Bank 还能为我们的代码除臭。一个令人讨厌的现象是,为存储汇率而创建的键--例如USD->EUR--在Portfolio 中随处可见。这种气味是一个可靠的指标,表明我们的抽象存在漏洞。通过将汇率表示(键和值)保留在Bank 中,我们将简化Portfolio 执行评估的方式。
提示
当责任从一个实体溢出到另一个不属于它们的实体时,这就是所谓的 "泄漏抽象"。 用乔尔-斯波斯基(Joel Spolsky)的话说就是"所有非三维抽象在某种程度上都是有漏洞的。然而,应该通过重新设计来堵住漏洞。
依赖注入
在确定了对这个新实体的需求之后,下一个问题是:Bank 与其他两个现有实体Money 和Portfolio之间的依赖关系应该是怎样的?
显然,Bank 需要Money 才能运行。Portfolio 需要Money 和Bank 。前者是聚合关联,后者是接口依赖;Portfolio 使用Bank 中的convert 方法。
图 11-1显示了我们程序中的三个主要实体、它们的职责和相互依赖关系。
图 11-1. 程序中的三个主要实体
Portfolio 对Bank 的依赖性降到了最低:Bank ...