【设计模式系列】一、什么是设计模式?

今天开始,会给大家陆续分享一个新的系列——设计模式。

维基百科对设计模式的定义:

在软件工程中,设计模式(Design Pattern)是对软件设计中普遍存在(反复出现)的各种问题,所提出的解决方案。这个术语是由埃里希·伽玛(Erich Gamma)等人在 1990 年代从建筑设计领域引入到计算机科学的。设计模式并不是直接用来完成代码的编写,而是描述在各种不同情况下,要怎么解决问题的一种方案。

看完上面的介绍,估计你也是云里雾里,看着这些干巴巴的理论,对于我们好像也没有什么帮助。而且面试的时候,面试官也不会问:“什么是设计模式”,“有多少种设计模式”之类的问题。

其实早在1995 年,GoF(Gang of Four,四人组/四人帮)合作出版了《设计模式:可复用面向对象软件的基础》一书,共收录了 23 种设计模式,从此树立了软件设计模式领域的里程碑,人称「GoF设计模式」。

在前端开发中,设计模式似乎离我们很远。然而对照这23种设计模式 ,我们会发现自己在开发过程中不知不觉地使用了其中的某一种,只是我们无意识。

当然,了解设计模式,对于工作以及晋升,还是很有帮助的。

设计模式到底是什么

设计模式其实就是一种工作经验的总结,通过实际项目,总结出来的一套方法论。

“理论指导实践”,最终的目的就是为了更好的代码重用,可读性,可靠性,可维护性。

设计模式是针对软件设计中常见问题的工具箱,其中的工具就是各种经过实践验证的解决方案。即使你从未遇到过这些问题,了解模式仍然非常有用,因为它能指导你如何使用面向对象的设计原则来解决各种问题。

设计模式既然是一套理论,是一种约定和规范,那么它也就有自己的原则。

总体来说,其六大原则包括:

  • 开闭原则
  • 里氏替换原则
  • 依赖反转原则
  • 接口隔离原则
  • 最小知道原则
  • 合成复用原则

我们先逐个了解一下相关概念。

开闭原则(Open Close Principle)

理解开闭原则,就要了解开和闭。这里的开是指对扩展开放,闭是说对修改关闭。想想我们有一套实现、提供一个服务,这样的程序需要能够随时进行扩展、随时支持第三方的自定义配置,但是不能去修改已用的实现代码。

比如我们做了一个 UI 组件轮子,业务方在使用时显然不能够修改我们的代码,但是仍然可以进行扩展。再比如著名的 Draft.js 库,在实现一个编辑器时,提供了灵活的插件机制,实现了热插拔效果,使得整个程序的扩展性好,易于维护和升级。甚至 Redux 库、Koa 库等基本所有库都有开闭原则的体现。

对于面向对象类型的语言来说,想要严格遵守开闭原则,往往需要使用接口和抽象类,这个我们会在具体设计中再次提到。

里氏替换原则(Liskov Substitution Principle)

里氏代换原则就稍微有些抽象,但它是面向对象设计的基本原则之一。里氏代换原则要求,任何基类可以发挥作用的地方,子类一定可以发挥作用。

这句话怎么理解呢?想想我们的继承实现,里氏替换原则就是继承复用的基础。只有当派生类可以随时替换掉其基类,同时功能不被破坏,基类的方法仍然能被使用,这才是真正的继承,继承才能真正地实现复用,当然,派生类也需要随时能够在基类的基础上增加新的行为。

事实上,里氏代换原则是对开闭原则的补充。

依赖反转原则(Dependence Inversion Principle)

该原则要求针对接口编程,依赖于抽象。更多理论内容我并不打算展开,后续在程序设计中会结合实例提及。

接口隔离原则(Interface Segregation Principle)

接口隔离的意思或者目的是减少耦合的出现。在大型软件架构中,使用多个相互隔离的接口,一定比使用单个大而全的接口要好。

最少知道原则,又称迪米特法则(Demeter Principle)

最少知道顾名思义,是指:一个系统的功能模块应该最大限度地不知晓其他模块的出现,减少感知,模块应相对独立。

合成复用原则(Composite Reuse Principle)

合成复用原则是指:尽量使用合成 / 聚合的方式,而不是使用继承。这是很有意思的一点,基于原型的继承在很多程度上「优于」基于类的继承,原因就在于基于原型的继承模式体现了可组合性,能够规避「大猩猩和香蕉」等问题的出现。组合是非常优秀的编程思想,这一点在函数式编程范畴中得到了最大程度的印证。

设计模式分类

不同设计模式的复杂程度、 细节层次以及在整个系统中的应用范围等方面各不相同。我喜欢将其类比于道路的建造:如果你希望让十字路口更加安全, 那么可以安装一些交通信号灯, 或者修建包含行人地下通道在内的多层互通式立交桥。

最基础的、 底层的模式通常被称为惯用技巧。这类模式一般只能在一种编程语言中使用。

最通用的、 高层的模式是构架模式。开发者可以在任何编程语言中使用这类模式。与其他模式不同, 它们可用于整个应用程序的架构设计。

此外,所有模式可以根据其意图或目的来分类。而我们一般会将设计模式分成

  • 创建型(Creational Patterns)

创建型的五种设计模式提供了更加灵活的对象创建方式,同时可以隐藏创建的具体逻辑。与直接使用 new 运算符实例化对象相比,这些模式具有更强的灵活性以及可定制性。

  • 结构型(Structural Patterns)

结构型的七种设计模式关注类和对象的组合,结合继承的概念,这些设计模式能使得对象具有更加灵活的功能设定。

  • 行为型(Behavioral Patterns)

行为型的十一种设计模式聚焦于对象和类之间的通信,这是构建大型程序架构必不可少的环节。

设计模式的学习

设计模式使得我们的代码编程真正意义上实现工程化,定义设计模式是软件工程的基石脉络,一点都不为过。

其实设计模式不用刻意的去学习,套用。因为设计模式的思想都是在实际工作中总结出来的,这需要一个长期有耐心的过程培养。

之后的一系列文章中,我们会结合实际开发中的相关需求,继续与大家一块探讨具体的设计模式。