最近的一两个月里,我一直在研究各类的模式:设计模式、架构模式、容器模式,以及其它一些特定领域的模式(如并行计算模式)等等。
经历了一番买书、读论文、读代码,我发现了以前对于模式的理解不够深刻。也因此呢,这篇文章就是用来记录一些缺乏的东西,诸如于模式语言、模式的模式等。
PS:为了方便阅读,本文的书名使用都是简写模式,全称在最后的相关资料中。
模式重谈
为了避免出现类似于 Datum 是最好的语言这一类的问题,在那之前,我得先阐述一下对于模式的看法:
- 模式是对于惯用方式的总结,不限于编程,有相当多的人习惯了使用各种设计模式,但是他并不知道这是何种模式。它是一个概念字表,用于快速沟通。
- 模式是解决方案,满足锤子定律,只有遇到特定的问题时,你才会需要它。
- 模式是适用于特定场景的,大部分的模式对于当前所处的系统是无用的,往往只有少数的模式是适合的。
- 模式是知识体系的展现,掌握模式的多少,更多的说明见多识广,并不一定代表真实的代码水平和能力。
- 模式需要刻意练习,学习模式是一个漫长的过程,所以总会遇到理解解决、使用错误的情况,不要担心。
- 模式种类繁多,计算机行业普遍认同的是:模式的起源是亚历山大的《建筑的永恒之道》。在更早的时间里,也还有对应的总结,但是这里是最体系化的技巧。
除了设计模式之外,我们所处的行业还有大量的其它模式:
- 容器设计模式。应对于云原生应用下一系列复杂的分式场景,Google 的工程师发表了相关的论文对此进行总结,常见的有 Sidecar、Adapter、Ambassador 等。
- 架构模式。架构模式是在给定上下文中解决软件架构中常见问题的通用,可重用的解决方案。除此,一些常见的架构风格,如微服务、事件驱动架构等,从大类上来说也被归纳到架构模式中。
- ……
所以,你会发现这些模式只是人们对于惯用法的总结。
寻找模式
回过头来看,当我们会发现进入一个新的领域,进行相关领域的架构设计之时,我们会不断搜寻各类的资料,而后再去贴合到设计中去。实际上呢,我们是在寻找该领域的模式,有了这些模式,便可以照猫画虎的设计一个系统,而不会出现太大的问题。
运气好的情况下,我们甚至于能比在这个领域的大多数人做得更好 —— 因为我们所掌握的是解决这一类问题的模式。
这时,我们已经有一个很有优势性的套路,以帮助我们更好地进入新的领域。但是呢,作为一个新的领域的初来者,往往不知道到底应该采用哪一种模式,也不确定模式之间存在何种关系。
相关书籍:《设计模式》
模式归类:目录、集合、仓库
在一个软件系统中,模式很少独立存在,往往是多个模式相互组合,用于解决特定的问题。而其中的一种组织方式的模式就是模式集合。随后,根据不同的需求,再对进行分门别类。如《POSA 5》所介绍的几种方式:
- 即时(ad hoc)组织。
- 根据层次划分:根据抽象、粒度和规模的层次划分。
- 根据领域组织:电信、金融、电子商务等。
- 根据分区组织:归属于架构的哪一部分。如层、阶层(tier)、组件和包都是分区的例子
- 根据意图组织:如 POSA、GoF 的 23 种设计模式、DDD
- ……
接着,让我们来看几个分类示例。
设计模式的组织
在《设计模式》一书中,引入的概念是『设计模式空间』,在这里它们被分为了三大类:
- 创建型模式:单例模式、抽象工厂模式、建造者模式、工厂模式、原型模式。
- 结构型模式:适配器模式、桥接模式、装饰模式、组合模式、外观模式、享元模式、代理模式。
- 行为型模式:模版方法模式、命令模式、迭代器模式、观察者模式、中介者模式、备忘录模式、解释器模式、状态模式、策略模式、职责链模式、访问者模式
其划分的两条准分别是: 目的准则,用来完成什么工作;范围准则,指定的模式是用于类还是用于对象。
DDD 的组织
《领域驱动设计》一书其中也是一本模式合集,这就是为什么这本书不易于读懂的原因之一。另外一个原因则是,翻译这本书的人没有理解好什么是统一语言。
在 《领域驱动设计》 一书以多种形式组织了模式,依次的四个部分是(PS:个人临时总结):
- 运用领域模型 —— 『模型知识提取的模式』
- 模型驱动设计的构造块 —— 『模型设计的模式』
- 通过重构来加深理解 —— 『模型优化的模式』
- 战略设计 —— 『模型边界划分的模式』
而这个顺序其实也是我们在实施 DDD 过程中的设计过程,而后再进行层次化的组织,如『战略设计』部分根据不同的意图,又分为不同的合集:
- 保持模型的完整性,如限界上下文、上下文地图等
- 精炼:核心域、通用域等
- 大型结构:演化秩序(Evolving Order)、系统隐喻等
所以从结构上来看,《领域驱动设计》是一本由小而大的书,阅读难度略大,需要一定的经验。
模式分类的意图
我们把『如何应用设计模式看作是一个问题域』,那么模式分类就是在这个问题域里的一种解决方案。
在计算机的不同的复杂领域里,如并行编程、架构设计等等,它们本身是包含了大量的模式。而有了对于这些模式的进一步分类,对于我们应用模式会有更大的帮助 —— 至少在应对同一个次级问题时,我们可以寻找可能的替代模式。
不过呢,多数时候,我们往往不知道的是:我们遇到的问题是什么?
角落里的模式语言
如 《POSA 5》所定义的一样:模式语言与具体领域高度相关,并且能对这一类系统提供具体而周全的引导,具体包括以下几项:
- 要解决的主要问题有哪些?
- 这些问题应该以什么样的先后次序解决?
- 解决一个给定问题,有什么可用的替代解决方案?
- 怎样处理问题之间的依赖性?
在有“周边” 问题存在的情况下,怎样最有效地解决单个问题?
简单来说,模式语言针对于某个特定的问题(如并行编程)所抽象的模式,并包含了他们之间的关系等,能用于系统性地解决这一类问题。
书中还提到 了 Gerard Meszaros 的观点“模式语言可以用来指导生手创建系统”。Aha,这不就是我们想要的东西吗?作为一个进入新领域的新人,我们需要这么一个模式语言。尽管模式语言可以帮助我们解决这一类的问题,但是它也意味着它自身需要:充分覆盖、进展可持续、紧密集成。依照这一系列的前提,它意味着设计这个模式语言的人应该是业内专家,并且模式本身应该是不断演进的。
因此,当我们把如何实施和使用模式看作是我们的问题时,那么模式语言解决这一类问题的模式。
分布式计算的模式语言
《POSA》系列大概是在中文世界 里,我们所能找到的最好的资料。因此,这里再次以《POSA 4》作为例子,《POSA 4》全称是《面向模式的软件架构:分布式计算的模式语言》。
先来看图(图中的圈内表示的是问题域,连续表示的是他们的关系,每个问题域下包含了相关的模式):
POSA Pattern Language
举例来说开头的『From Mud to Structure』(从混沌到结构)就是一个大的问题域,对应于这个问题域则包含了一系列的模式,如:MVC、分层、PAC、微内核等。同时,针对于这个问题题来说,如果我们还要数据库访问,那么我们从数据库访问中获得对应的模式,以此来完善我们的设计。
然后,在我们进入了具体的模式/问题域之后,它还详细介绍了如何实现对应的模式。如分层:
POSA Layer
有了这系列的配合,我们便可以完善整个系统的设计。
微服务的模式语言
接着,让我们来看看《微服务架构设计模式》中关于微服务的架构模式概述:
微服务模式语言
从上图中,我们可以看到由 Chris Richardson 整理的这个微服务模式语言,对语言进行了多层的分类,并指明了它们之间的关系。颇为遗憾的是这个模式语言只包含了关系,缺少了一些相关关系的描述。
虽然如此,但是从总体上来说,它还是能在一定程度上帮助我们设计微服务。
相关书籍:《POSA 4》、《POSA 5》、《微服务架构设计模式》
模式的模式
从模式再模式归类,再到模式语言,我们已经有了整套的方案。最后,我们就剩下一些有意思的问题,诸如于如何发现新的模式?如何对现有的模式进行一些抽象。
对于『模式的模式』的理解,有助于我们更好地理解好设计模式。对于设计模式的理解之后,只需要理解其背后的模式,就不需要再去熟记每个设计模式。
所以,我们就来到了元素模式,依据的它也是来自于一本书《元素模式》。
元素模式:设计模式的模式
模式是来源于对惯用法的总结,而诸如于元素模式则是对于设计模式的提取,即模式中的模式。元素模式(Elemental Design Patterns)的核心要义是一组面向对象的基本概念。
对 OO 中的设计模式进行更细致的拆分,我们就能得到位于其背后的模式。作为其中的核心元素模式便是:创建对象、检索、继承和抽象接口。于是,如书上所说,结合这四个 EDP,我们可以创建对,并实施特定的保证,在运行时建立自此的关联,并从一种类型出发建立其他类型,以及创建出声明,并带有关于未来的、未定的类型的保证。
而我们在实施方法调用时,也被抽象了四个 EDP:递归、委托、重定向和集聚,以此构成了设计的砌块。
架构模式的模式
最后就回到了我想抽象的问题,那么架构模式其背后的模式又有什么呢?我试着进行了简单的拆解:
- 契约。输入与输出、API 等。
- 分割。隔离变化、明确职责等。
- 约束。功能需求和非功能需求、性能等。
- 封装。接口封装。
- 协作。协作风格等
- ……
当然了,我还需要他们进行重新命名,以构建在架构模式领域的统一语言。
其它
尽管,它有些复杂,但是依旧很有意思。
相关资料
《元素模式》
《设计模式》 -> 《设计模式:可复用面向对象软件的基础》
《POSA 4》 -> 《面向模式的软件架构,卷 4:分布式计算的模式语言》
《POSA 5》 -> 《面向模式的软件架构,卷 5:模式与模式语言》
《领域驱动设计》 -> 《领域驱动设计:软件核心复杂性应对之道》
本文转载自微信公众号「 phodal」,可以通过以下二维码关注。转载本文请联系 phodal公众号。