EBI 架构
实体边界交互器(EBI)架构已经由Robert C. Martin在他关于清洁架构的演讲中(我将在后面的文章中讨论)中广为人知。
但是,这种模式是由Ivar Jacobson在1992年出版的,在他的书《面向对象的软件工程:一种用例驱动的方法》中。当时,Jacobson实际上称它为实体-接口-控制,但名称被更改,以便"接口"不会与"接口"语言结构(某些语言甚至没有)或"用户界面"混淆,并且"控制"不会与MVC控制器混淆。
实体
Entity 对象保存系统使用的数据以及自然耦合到此数据的所有行为。每个实体对象都表示一个与问题域相关的概念,其中保存标识和弹性(持久性)数据。Jacobson告诉我们,Entity对象应该包含当实体本身发生变化时会发生变化的逻辑,即。如果它所包含的数据结构发生变化,则对该数据的操作也需要更改,因此它们也应位于实体中。
有趣的是,雅各布森早在1992年就已经发出了警告:
初学者有时可能只使用实体对象作为数据载体,并将所有动态行为放在控制对象中[…]。但是,应避免这种情况。[…]相反,应该在实体对象中放置相当多的行为。
伊瓦尔·雅各布森 1992年,第134页
这是对我们现在所知的"贫血实体"的警告。
边界(接口)
边界对象对与系统的接口进行建模。
[…]与系统接口有关的所有内容都放置在接口对象中
伊瓦尔·雅各布森 1992年,第134页
依赖于系统环境的所有功能(工具和交付机制)都属于边界对象。
系统与执行组件的任何交互都通过边界对象。正如 Jacobson 所描述的那样,参与者可以是像客户或管理员(操作员)这样的人类用户,但它也可能是非人类"用户",如警报、打印机或第三方 API。
交互器(控件)
Interactor 对象将保留与任何其他类型的对象没有自然关联的行为。
Sutch 行为通常由对多个实体的操作组成,最终将某些结果返回给边界对象。
在接口对象和实体对象获得其部件后仍然存在的行为将放置在控件对象中
伊瓦尔·雅各布森 1992年,第185页
这意味着所有不适合边界或实体的行为都将放置在一个或多个控件对象中。
因此,Jacobson 认为 Control 对象不仅是编排用例的对象,而且还认为它是具有与用例相关的行为但不是边界也不是实体的任何对象。
与我的经验相比,我会说他将交互者称为我所谓的应用程序服务(编排用例)和域服务(包含域行为但不是实体)。
这个中间交互器对象非常重要的原因是,如果我们不使用它们,我们将把它们的特定用例逻辑放在实体中。但是,实体在多个用例中使用,因此它们具有通用用法。通过将特定的用例逻辑放在一个实体中,我们使其在多个边界中可用,这些边界最终可能会像通用逻辑一样使用它,我们最终可能会将其更改为另一个边界,从而增加其复杂性以及破坏使用它的其他用例的机会。
为什么有 3 种对象类型?
雅各布森说,当时,其他OO方法将把所有这些职责放在实体本身,但是,他(和他的合作者)更喜欢将这些职责分为3种对象类型,因为这将使系统更能适应变化。
[…]所有系统都会改变。因此,稳定性的发生是指所有更改都是局部的,也就是说,只影响(最好)系统中的一个对象。
伊瓦尔·雅各布森 1992年,第135页
因此,目标是通过封装责任,在系统的变化中具有地方性。如果我们考虑一下,Jacobson含蓄地谈论了**单一责任原则,该原则于10年后由Robert C. Martin在他的精彩著作"敏捷软件开发,原则,模式和实践**"中发表。
结论
就像在MVC模式中,模型表示整个后端、所有实体、服务及其关系一样,EBI模式将边界视为与外部世界的一个完整连接,而不仅仅是一个视图、控制器或一个接口(语言结构)。边界表示整个表示层,在 MVC 中对应于视图和控制器。EBI 中的实体代表持有数据的实际实体,结束其关联的行为,而交互器对象在表示层和实体之间建立连接,它们就是我所说的应用程序服务和域服务。
EBI 模式之于后端,就像 MVC 之于前端。它们不是彼此的替代品,而是相辅相成的。如果我们将它们放在一个单一的模式中,我们可以称之为视图 - 控制器 - 交互器 - 实体。