Introduction
这篇博客我将和大家讨论一下有关软件设计模式的问题。设计模式有很多种,在实际使用中我们可能并不是完完整整地把一个模式套进去,但更重要的是我们理解每个模式的基本思想,从而帮助我们更好地构建应用。这篇博客我将会based on一个我认为比较好的博客(请看reference),介绍8种常用的设计模式,并且结合我自己的实际开发经历,去解释其中几个我熟悉的。
8 Common Design Pattern
Layered Pattern (层级模式)
层级模式把业务逻辑切分不同层级的子任务,每一个子任务都是一个抽象。通常来说有4层模型,包括:
- Presentation Layer (UI Layer):表示层。这一层负责展示UI,与用户的交互;
- Application Layer (Service Layer):应用层。这一层负责处理服务逻辑,也就是提供API支持用户的基本操作;
- Business Logic Layer (Domain Layer):业务逻辑层。这一层负责处理业务逻辑,比如一个登录的功能,Application Layer提供了接口给用户输入用户名和密码,至于校验的部分就属于Business Logic Layer;
- Data Access Layer (Persistence Layer):数据层。这一层负责处理持久化数据,通常来说应用都需要持久化数据,这一层就负责处理数据的CRUD。
这种模式最大的优点就是抽象,某一层对上一层是透明的,只通过提供接口来提供服务,外部不需要知道它具体是如何实现的。目前来说这更像是一种代码习惯,我认为在日常的编程中都应该有这种意识。
Client-Server Pattern (CS模式)
客户端服务器模式是一种非常通用的模式,这里特别提到,这里的客户端和服务器是很广泛的概念,客户端同时也可以是别人的服务器,服务器同时也可以是客户端。客户端和服务器分别具有以下功能:
- Server:服务器服务多个客户端,这里的花样很多,比如负载均衡,使得多个服务器同时服务多个客户请求;
- Client:客户端发起请求到服务端。
Master-Slave(主从模式)
主从模式是一种非常常用的调度模式,一般来说会有1个主,多个从。master服务负责分发任务,归约结果;slave服务负责计算任务,汇报结果。所有的从服务器都是一样的。这里我可以举两个例子:
- 我之前做过数据迁移相关的项目,主要也是使用了这个架构。master服务从数据库中拉取迁移任务,然后放到队列中;slave服务从队列中消费到迁移任务,然后执行具体的迁移动作,最后把结果更新到数据库。这样做的好处是如果我需要扩大吞吐,我可以只扩展slave服务的数量,或者只调整数据库拉取batch的大小,相对来说比较灵活。同时,某一个slave服务的迁移出了问题,并不会影响整体的功能,这个是非常重要的。
- 数据库的主从。数据库中广泛应用了这种模式,一般来说写请求只能由master处理,然后通过节点间的一致性同步协议更新到所有的slave节点,而读请求则可以读所有的slave,这样也算是负载均衡的一种。当然这个更像是架构设计方面的内容,而不是开发模式。
Pipe-Filter(管道过滤器模式)
管道过滤器模式听起来很陌生,通俗点说就是流水线。通常是配合消息队列进行开发。这种模式用于处理流数据,每一个处理部分都是一个单独的、封闭的组件。这里也举两个例子:
- 比方说邮件系统中,收取外部邮件,大概的流程可能是:检查header判断是否垃圾邮件 -> 检查内容有没有病毒 -> 解析成结构化内容 -> 存入到数据库中。我们可以把多个步骤合在一个component中做,也可以拆开,component之间是通过消息队列沟通,所以是非常灵活的,也能很有效地应对流量高峰。同时,最大的优点是可以支持很灵活的拔插,可以随时增加或减少功能。
- 编译器的工作原理实际上就是管道过滤,语法分析 -> 解析 -> 语义分析 -> 代码生成。
Broker Pattern(代理模式)
Broker模式通过解耦组件来构建分布式系统,broker组件主要负责协调其他所有组件的通信。服务器向broker发布功能,客户端向broker请求服务,broker再把这个请求路由到合适的服务器。
- Kafka等消息中间件。消费者和生产者都向broker注册,然后发送请求,分别拉取消息或者推送消息。
- 如果某个功能有多个服务需要调用到第三方的API,那么最好能抽取出来一个broker来管理这个第三方API的调用,因为API调用涉及到了权限、频率、链接等各种问题,如果有独立的broker来处理会更加清晰和简洁,也易于控制。
这种架构最大的好处就是支持非常灵活的变动,比如消费者、生产者的数量改变了,broker就可以很快知道并且协调通信。
P2P Pattern(对等模式)
这个模式顾名思义就是没有主从,每个节点都是平等的。好处就是没有单点故障的危险,不会因为master出错而导致整个系统崩溃,也不容易受到大规模的攻击。如果设计合理的话能够最大限度地利用各个节点的资源,提供系统整体的吞吐。目前的应用有文件共享以及多媒体协议。
EventBus Pattern(事件总线模式)
EventBus模式更像是一个消费-生产者模式,相当于有一个生产者把各类事件都发布到一个消息总线,然后订阅者订阅不同的事件类型。消息发布到监听者订阅的通道,监听者就会收到通知。主要组件有4个:
- 事件源:可以是一个服务,也可以是多个服务。例如可以是数据库的binlog,也可以是很多服务收集到的日志信息;
- 监听者:想要处理某个事件类型的服务;
- 通道:事件总线中的一个通道,相当于消息类型,同一种类型的消息在同一个通道;
- 事件总线:所有消息的队列
EventBus常用的地方一个是监听数据库的binlog做异步处理,另一个是Android中通过监听EventBus来处理各种通知。
Model-View-Controller (MVC模式)
MVC模式是非常经典的交互式应用程序设计模式,许多Web应用都是基于这个设计模式的。顾名思义由三部分组成:
- Model:主要处理业务逻辑和核心数据;
- View:主要处理用户展示部分;
- Controller:主要处理用户交互,如用户的输入
解耦成这三部分的原因是提高代码重用率,同时能够把相对独立的模块分离开来,便于维护。
Summary
这篇博客大概介绍了常用的8个软件架构设计模式,我认为设计模式对于软件开发是非常重要的,但我们不能硬套某个模式,而是要充分理解每一个模式的优缺点,以及使用场景,这样在使用的时候才能找到最合适的模式来写代码。