分层架构
分层架构的一个重要原则是每层只能与位于其下方的层发生耦合。分层架构可以简单分为两种,即严格分层架构和松散分层架构。在严格分层架构中,某层只能与位于其直接下方的层发生耦合,而在松散分层架构中,则允许某层与它的任意下方层发生耦合。
分层架构的好处是显而易见的。首先,由于层间松散的耦合关系,使得我们可以专注于本层的设计,而不必关心其他层的设计,也不必担心自己的设计会影响其它层,对提高软件质量大有裨益。其次,分层架构使得程序结构清晰,升级和维护都变得十分容易,更改某层的具体实现代码,只要本层的接口保持稳定,其他层可以不必修改。即使本层的接口发生变化,也只影响相邻的上层,修改工作量小且错误可以控制,不会带来意外的风险。
要保持程序分层架构的优点,就必须坚持层间的松散耦合关系。设计程序时,应先划分出可能的层次,以及此层次提供的接口和需要的接口。设计某层时,应尽量保持层间的隔离,仅使用下层提供的接口。
关于分层架构的优点,Martin Fowler在《Patterns of Enterprise Application Architecture》一书中给出了答案:
1. 开发人员可以只关注整个结构中的某一层。
2. 可以很容易的用新的实现来替换原有层次的实现。
3. 可以降低层与层之间的依赖。
4. 有利于标准化。
5. 利于各层逻辑的复用。
分层架构也不可避免具有一些缺陷:
降低了系统的性能。这是显然的,因为增加了中间层,不过可以通过缓存机制来改善。
可能会导致级联的修改。这种修改尤其体现在自上而下的方向,不过可以通过依赖倒置来改善。
六边形架构
解决了传统的分层架构所带来的问题,实际上它也是一种分层架构,只不过不是上下或左右,而是变成了内部和外部
领域模型位于整个框架的最中间,属于高层次模块。基础设施处于最外层,属于低层次模块。
为什么会出现六边形架构?
传统的分层架构具有广泛的应用,例如经典的三层架构,把系统分为表示层、业务逻辑层、数据访问层。在Martin Fowler的《企业应用架构模式》一书中做过深入阐述,本书04年出版,时至今日分层架构仍然是常用的设计方法,分层架构可以降低耦合、提高复用、分而治之,但同时也还是存在一些问题:
- 应用逻辑在不同层泄露,导致替换某一层变得困难、难以对核心逻辑完整测试:你是否有过困惑,代码到底应该放在哪个层,虽然定义了各层的职责,但是总有人不严格遵循层次的分界,对于三层架构,常常会出现业务逻辑写在了表示层,或者业务逻辑直接和数据访问绑定。
- 分层不清晰、相互依赖严重,系统无法方便地进行自动化测试 ,传统的分层架构是一维的结构,有时应用不光是上下的依赖,可能是多维的依赖,这时一维的结构就无法适应了。
- 另外应用程序之间的相互驱动变得很困难,有时甚至不可能的
在许多组织中反复尝试的解决方案是在体系结构中创建一个新层,并保证这次确实没有将业务逻辑放入新层中。 但是,由于没有机制来检测何时发生违反该承诺的情况,该组织发现,几年后,新层被业务逻辑弄得乱七八糟,旧问题又出现了。
2. 架构思想
- 明确区分应用程序,领域和基础结构三个层
- 依赖关系是从应用程序和基础结构再到领域
- 使用端口和适配器隔离它们的边界
第一个原则:分层
应用程序端(Application):这是用户或外部程序将与应用程序进行交互的一面。API 的 HTTP 路由,JSON 序列化都在这里,有点类似于 MVC 的 controller 层。
领域(Domain):左右两端隔离的部分,它包含所有涉及并实现业务逻辑的代码。
基础架构(Infrastructure):在这里我们可以找到您的应用程序需要什么,它可以驱动什么工作。它包含基本的基础结构详细信息,例如与数据库交互的代码,对文件系统的调用或处理对您依赖的其他应用程序的 HTTP 调用的代码。
第二个原则:依赖关系进入域
内部相关的代码不能泄露到外部。所谓的泄露是指不能出现内部依赖外部的情况,只能外部依赖内部,这样才能保证外部是可以替换的。对于驱动者适配器,就是外部依赖内部的。但是对于被驱动者适配器,实际是内部依赖外部,这时需要使用依赖倒置,由驱动者适配器将被驱动者适配器注入到应用内部,这时端口的定义在应用内部,但是实现是由适配器实现。
第三个原则:边界与接口隔离
总而言之,应用程序代码通过业务代码中定义的接口(此处为 IRequestVerses)驱动业务代码。商业代码通过同样在商业代码(IObtainPoems)中定义的接口来驱动基础架构。这些接口充当**内部和外部之间的显式绝缘体**。
简单的说,就是应用程序和基础架构都直接依赖业务代码提供的接口直接驱动,我们不需要关注业务代码是怎么实现的。
3. Metaphor
将这种架构模式比喻成端口适配器或者六边形。
Adapter起什么作用
它负责将与外设交互的数据(包括命令、query)转化为 Application 可以理解的信息(业务module),并通过内部系统提供的接口进行业务逻辑的处理。
Port
对于软件系统来讲,port 上端口协议的体现就是 api,即业务系统对外暴露的接口,一个端口可以有多个适配器。比如一个系统提供产口的信息的展示,这时候该信息可能需要在 app,web 或者作为远程服务对外提供产品信息,这时候由 Application 是提供一个 query 接口,并返回一个对象,至于要将其转换成 app,web 或者远程服务 json 格式,则由 adapter 来完成。
参考: