哈哈龙 2018-09-25
Singleton(单例模式)、仓储模式(repository)、工厂模式(factory)、建造者模式(builder)、装饰模式(decorator)……大概每个上课听讲的程序员都不会陌生——软件的设计模式为我们提供了针对现有的、重复出现的问题以可靠的解决方案。
在软件架构方面同样存在类似的机制,通用的、可重用的解决方案在给定上下文中的软件体系结构中经常出现的问题。不同的软件架构模式各有千秋,以下是目前较为主流的5种软件架构模式。
分层模式(Layered Pattern)
分层模式大概是最知名的软件架构模式之一,有大量的开发者使用,但并不知道它的名字。分层模式将代码拆分为“层”,每个层都有一定的责任,并为更高“层”服务。
分层模式并没有规定层的数量,但通常会有以下结构:
分层模式的想法是用户通过执行某些动作(例如点击按钮)在表现层启动一段代码。随后,表现层调用应用层、进入业务层,最后持久层将所有内容存储在数据库中。简单来说,分层模式中的高层调用并依赖低层。
根据应用复杂程度,我们会看到很多相应的变体。例如某些应用会省略应用层,而某些应用会添加缓存层,甚至会出现两层合一的情况。
层责任
如上所述,每层有每层的责任。表现层包含应用的图形设计和处理交互的代码。理论上来讲,我们不应该在这一层添加任何与user interface无关的逻辑。
业务层是放置特定业务问题模型和逻辑的地方。
应用层位于业务层和和表现层之间。一方面为表现层提供业务层抽象,另一方面为应用层提供放置某些不适合放置于业务层或表现层的某些协调逻辑。
持久层包含访问数据库层的代码,而数据库层是底层数据库技术,例如SQL Server、MongoDB。持久层是用于操作数据库的代码集:SQL语句、连接详情等。
优势
劣势
适用于
微内核模式(Microkernel)
当应用程序有一组核心职责和一组可互换的部件时,微内核模式(或插件模式)非常有用。微内核将提供应用程序的入口点和一般流程,而不需要真正了解不同的插件在做什么。
例如任务调度,微内核可以包含所有的调度和触发逻辑,而插件负责特定的任务。只要插件遵循特定的API,微内核就可以出发它们,而不需要了解实现的细节。
另一个例子是工作流。工作流的实现包含诸如不同步骤的顺序、评估步骤的结果、决定下一步的内容等概念,步骤的的具体实现对于工作流的核心代码并不重要。
优势
劣势
适用于
命令职责查询分离模式(CQRS)
CQRS是Command and Query Responsibility Segregation的缩写。这种模式的核心概念是应用具有完全分离的读取操作和写入操作,这也意味着用于写操作(命令)的模型和读取(查询)不同。此外,数据将存储在不同的位置。在关系数据库中,意味着将存在用于命令模型的表和用于读取模型的表。一些实现甚至将不同的模型存储在完全不同的数据库中,例如用于命令模型的SQL Server和用于读取模型的MongoDB。
CQRS模式通常和事件溯源(Event Sourcing)结合,下一小节会讲到。
CQRS如何工作?当用户执行操作,应用会向命令服务器发送命令。命令服务从命令数据库中检索所需的任何数据,进行必要的操作并将其存储回数据库中,然后它通知读取服务,以便更新读取模型。如下所示:
当应用需要向用户显示数据时,它可以通过调用读取服务来检索读取模型,如下所示:
优势
劣势
适用于
事件溯源模式(Event Sourcing)
这种模式不会将模型的当前状态存储在数据库中,而是将时间存储其中。因此,例如customer name发生变化时,该值不会存储在“name“列中,我们会存储一个”NameChanged“事件。
当我们需要检索模型时,我们将检索其存储的所有事件并在新对象上重新应用,即rehydrating an object。
用EXCEL记账来理解event sourcing会容易一些。当我们添加支出时,我们不需更改总值,而是增加一“行”,出现错误,也增加一“行”,最终利用EXCEL的公式自动计算出总数,而这里计算总数可以看作是读取模型。
您可以看到我们在添加Invoice 201805时发生了错误。我们添加了两条新行,而不是更改行,首先是一行取消错误的行,然后是新的正确行。这就是event sourcing的工作方式。你永远不会删除事件,因为它们无可否认地发生在过去。为了纠正情况,我们添加了新事件。
另外,请注意我们是如何获取总值的,它是上面单元格中所有值的总和。在Excel中,它会自动更新,因此我们可以说它与其他单元格同步。这就是一个读取模型。
Event sourcing通常会与CQRS同时使用,因为rehydrating an object可能会对性能产生影响,尤其是当实例中存在大量事件时。快速读取模型可以显着改善应用的响应时间。
优势
劣势
适用于
微服务模式(Microservices)
编写一组微服务实际上就是编写可以协同的多个应用。每个微服务都有自己独特的责任,团队可以独立于其他微服务开发它们。他们之间唯一的依赖是通信。当微服务相互通信时,我们必须确保它们之间发送的消息保持backwards-compatible(向后兼容)。这需要一些协调,特别是当不同的团队负责不同的微服务时。
如下图所示——
在上图中,应用调用一个中央API,将调用转发给正确的微服务。在此示例中,有为用户配置文件、库存、订单和付款提供单独的服务。我们可以想象这是一个用户订购应用。单独的微服务也可以相互调用。例如,支付服务可以在支付成功时通知订单服务。然后,订单服务可以调用库存服务来调整库存。
没有明确规定微服务有多大。在前面的示例中,用户配置文件服务可能负责用户的用户名和密码等数据,也可能负责家庭地址、头像图像、收藏夹等,也可以选择将所有这些责任分成更小的微服务。
优势
劣势
适用于
总结
各种软件架构模式很多时候会结合起来使用,他们之间并没有我们想象得那么水火难容。换句话说,没有万能的软件架构模式,如何选择取决于我们对于解决方案利弊的权衡。