六边形架构(端口与适配器)

合集下载
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

六边形架构(端⼝与适配器)
在六边形架构中,提出了⼀种具有对称性特征的架构风格。

在这种架构中,不同的客户通过“平等”的⽅式与系统交互。

需要新的客户吗?不是问题。

只需要添加⼀个新的适配器将客户输⼊转化成能被系统API所理解的参数就⾏了。

同时,系统输出,⽐如图形界⾯、持久化和消息等都可以通过不同⽅式实现,并且是可互换的。

这是可能的,因为对于每种特定的输出,都有⼀个新建的适配器负责完成相应的转化功能。

⾄此,我们有充⾜的理由认为,这将是⼀种具有持久⽣命⼒的架构。

现在,很多声称使⽤分层架构的团队实际上使⽤的就是六边形架构。

这是因为很多项⽬都使⽤了某种形式的依赖注⼊。

并不是说依赖注⼊天⽣就是六边形架构,⽽是说使⽤依赖注⼊的架构⾃然地具有了端⼝和适配器风格。

我们将对此做详尽的解释。

我们通常将客户与系统交互的地⽅称为“前端”;同样,我们将系统中获取、存储持久化数据和发送输出数据的地⽅称为“后端”。

但是,六边形架构提倡⽤⼀种新的视⾓来看待整个系统。

该架构中存在两个区域,分别是“外部区域”和“内部区域”。

在外部区域中,不同的客户均可以提交输⼊;⽽内部的系统则⽤于获取持久化数据,并对程序输出进⾏存储(⽐如数据库),或者在中途将输出转发到另外的地⽅(⽐如消息,转发到消息队列)。

每种类型的客户都有⾃⼰的适配器,该适配器⽤于将客户输⼊转化为程序内部API所理解的输⼊。

六边形每条不同的边代表了不同种类型的端⼝,端⼝要么处理输⼊,要么处理输出。

图中有3个客户请求均抵达相同的输⼊端⼝(适配器A、B和C),另⼀个客户请求使⽤了适配器D。

可能前3个请求使⽤了HTTP协议(浏览器、REST和SOAP等),⽽后⼀个请求使⽤了MSMQ的协议。

端⼝并没有明确的定义,它是⼀个⾮常灵活的概念。

⽆论采⽤哪种⽅式对端⼝进⾏划分,当客户请求到达时,都应该有相应的适配器对输⼊进⾏转化,然后适配器将调⽤应⽤程序的某个操作或者向应⽤程序发送⼀个事件,控制权由此交给内部区域。

我们不必⾃⼰实现端⼝
通常来说,我们都不⽤⾃⼰实现端⼝。

我们可以将端⼝想成是HTTP,⽽将适配器想成是.NET的HTTP请求处理管道。

或者,我们可以为MSMQ创建消息监听器,在这种情况下,端⼝是消息机制,⽽适配器则是消息监听器,因为消息监听器将负责从消息中提取数据,并将数据转化为应⽤层API(领域模型的直接客户)所能理解的参数。

按照功能需求来设计内部区域中的应⽤程序
在使⽤六边形架构时,我们应该根据⽤例来设计应⽤程序,⽽不是根据需要⽀持的客户数⽬业设计。

任何客户都可能向不同的端⼝发出请求,但是所有的适配器都将使⽤相同的API。

应⽤程序通过公共API接收客户请求。

应⽤程序边界,即内部六边形,也是⽤例(或⽤户故事)边界。

换句话说,我们应该根据应⽤程序的功能需求来创建⽤例,⽽不是客户数量或输出机制。

当应⽤程序通过API接收到请求时,它将使⽤领域模型来处理请求,其中便包括对业务逻辑的执⾏。

因此,应⽤层API通过应⽤服务的⽅式展现给外部。

再次提醒⼤家,这⾥的应⽤服务是领域模型的直接客户,就像在分层架构中⼀样。

以下代码表⽰通过WebAPI发布的RESTful资源。

当请求到达HTTP的输⼊端⼝时,相应的适配器将对请求的处理委派给应⽤服务:public class ProductControl
{
private ProductService productService;
[HttpGet]
public HttpResponseMessage GetProduct(string tenantId, string productId)
{
HttpResponseMessage rm;
Product product = productService.Product(tenantId, productId);
if(product == null)
{
rm = Request.CreateResponse(HttpStatusCode.NotFound);
}
else
{
rm = Request.CreateResponse<Product>(HttpStatusCode.OK,product);
}
return rm;
}
}
WebAPI路由构成了适配器的⼤部分功能,它们负责解析资源路径,并将资源参数转化为string类型参数。

ProductService(⼀个应⽤服务)实例是注⼊进来的,请求便是通过该ProductService将处理委派到应⽤程序内部的。

之后,Product对象将被序列化成json字符串,然后放在Response中,再由HTTP输出端⼝发出。

WebAPI并不是我们的关注点
WebAPI只是使⽤应⽤程序和领域模型的⼀种⽅式。

在这⾥,WebAPI并不重要,我们完全可以使⽤其它框架来完成相同的功能。

但不管采⽤哪种⽅式,不同的适配器都会将输⼊委派给相同的API。

图中右侧的端⼝和适配器,我们应该如何看待呢?我们可以将资源库的实现看作是持久化适配器,该适配器⽤于访问先前存储的聚合实例,或者保存新的聚合实例。

正如图中的适配器E、F和G所展⽰的,我们可以通过不同的⽅式实现资源库,⽐如关系型数据库、基于⽂档的存储、分布式缓存和内存存储等。

如果应⽤程序向外界发送领域事件消息,我们将使⽤适配器H进⾏处理。

该适配器处理消息输出,⽽刚才
提到的处理MSMQ消息的适配器则是消息输⼊的,因此应该使⽤不同的端⼝(即选择六边形的另外⼀条边)。

六边形架构的⼀⼤好处在于,我们可以轻易地开发⽤于测试的适配器。

整个应⽤程序和领域模型可以在没有客户和存储机制的条件下进⾏设计开发。

在测试时,我们可以⽅便地对ProductService进⾏替换,⽽⽆须考虑它是应该⽀持HTTP/REST呢,还是SOAP,或者是消息端⼝。

任何测试客户都可以在⽤户界⾯还未完成之前进⾏开发。

在选择持久化机制之前,我们可以在测试中采⽤内存资源库来模拟持久化。

更多的内存持久⼈实现细节,请参考资源库。

如此⼀来,我们可以在核⼼领域上进⾏持续开发,⽽不需要考虑那些⽀撑性的技术组件。

如果你采⽤的是严格分层架构,那么你应该考虑推平这种架构(推平严格分层架构),然后开始采⽤端⼝与适配器。

如果设计得当,内部六边形——也即应⽤程序和领域模型——是不会泄漏到外部区域的,这样也有助于形成⼀种清晰的应⽤程序边界。

在外部区域,不同的适配器可以⽀持⾃动化测试和真实的客户请求,还有存储、消息和其他输出机制等。

六边形架构的功能如此强⼤,以致于它可以⽤来⽀持系统中的其它架构。

⽐如,我们可能采⽤SOA架构、REST或者事件驱动架构;也有可能采⽤CQRS;或者数据⽹织或基于风格的分布式缓存;还有可能采⽤Map-Reduce这种分布式并⾏处理⽅式。

六边形架构为这些架构提供了坚实的⽀撑基础。

当然,能够提供这种基础的不只是六边形架构,但是⼀般默认使⽤这种架构,辅助使⽤其它架构。

相关文档
最新文档