架构层级的“开闭原则”2

三、系统扩展

假定我们需要在租赁流程结束的时候,给客户开具发票。可以设计一个Invoicing微服务来订阅RentalAgreementsSaved主题消息(消息中附加了租赁协议的ID)。当Status是“关闭状态”时,发票微服务可以从数据库中读取租赁协议的数据,并从Customers表中读取用户数据(Customers表和RentalAgreements表是相关联的)。有了上述信息,Invoicing微服务将可以向用户提供发票。过程如下图所示:

架构层级的“开闭原则”2

 我们扩展了系统的功能,但并没有变更系统的代码。只是利用了多个订阅者可以订阅同一个消息主题的机制。因此是的,OCP原则可以在架构层级得以应用。

迪米特法则
迪米特法则(Law of Demeter)又叫作最少知识原则(Least Knowledge Principle 简称LKP),就是说一个对象应当对其他对象有尽可能少的了解。

假设,我们对现有的功能很满意,并准备添加一个新的功能:向用户发出感谢信来感谢他或她使用了我们的服务。参考发票微服务的例子,我们可以同样从数据库中获得租赁协议和用户数据。但这样的设计效率不高,因为CustomerThanking服务根本不需要用到租赁协议的内容。事实上,这也违反了“迪米特法则”,而我们希望所有的系统都是符合良好的架构实现的。

架构层级的“开闭原则”2

 在一个超简化的系统模型中,我们可以定义如下的有界上下文:


租赁协议
客户 
车辆。
租赁专员:使用系统来办理租赁协议
租赁中介:通常情况下客户并不直接租车,而是通过代理人来租车

所有这些实体都出现在租赁协议中,但又自成有界上下文。因此,在最初设定消息格式的时候,我们可以根据正在进行的操作来引入主要的有界上下文。在本例中,初始的消息内容设计应该是下面的样子:

{
"Status":"Closed",
"RentalAgreementID":1234,
"CustomerID":8965,
"VehicleID":98263,
"RentalAgent":24352,
"Broker":6723
}

有了这样的消息结构,我们总算可以在不打破OCP原则和“迪米特法则”的情况下实现CustomerThanking微服务了。更不用说,我们还可以应用这样的消息结构来应付将来新的业务需要。

1、事件驱动系统给了我们很好的机会来在架构层级应用开闭原则。我们可以重用已有的代码,并且在未知的方向上实现功能的扩展。

2、然而,需要谨慎的设计事件的内容,同时警惕糟糕的设计可能引入的耦合的可能性。

3、要根据系统的目标来指导架构设计,为某一目标设计某种适用的架构(如,为大数据系统设计的流式数据)很可能对于另一目标来说是糟糕的设计(不适用于表征事实发生的事件驱动系统)。

4、领域驱动设计的有界上下文可以为事件内容的设计提供一些指导。

5、架构是关于决策和权衡,最大化应用开闭原则很可能意味着对“迪米特法则”的最小化遵循,必须谨小慎微地寻找一个平衡点。