发布于 

现在还需要学习设计模式吗?

最近面试了不少人,Java 和 dotNET 的都有,当问到设计模式时,大部分都只能说出单例和工厂,有些能聊聊其他的一些模式的,大多也没有在实际项目中用过。为了团队成员能有更好的编码能力,便有了重新写写设计模式的想法,写作也是一个重新学习的过程。

平时我们写代码,会有这样一些情况:

1、Leader 分配一个任务,比如要添加一个新功能,便找到相关的类,添加新的方法,然后就开始写业务逻辑,各种循环、判断,直到业务功能完成;

2、修复一个 Bug ,需要修改历史代码,某个方法被其他很多地方调用,怕改动引发出新的问题,有时复制一个相同方法进行修改;有时在方法参数中添加可空参数,然后根据参数值做判断。

上面的做法都是最直观、简单的方法,不需要动脑筋,一个程序员按照这种方法,工作一年便能轻松应对日常工作,工作十年,可以称之为拥有一年经验的熟练工,永远成不了高手。

如果一个团队都像这样做事,时间长了,会出现各种问题:

1、代码看着有很多类似的,但每个地方又有些差别,不敢随意修改;

2、Bug 修复异常困难,容易漏掉场景;

3、扩展功能会牵一发而动全身,需要加班加点,弄的疲惫不堪;

设计模式便是要打破我们的思维惯性,避免我们偷懒,强制我们思考的一个工具。

当再遇到上面提到的任务或 Bug 修复时,可以换一种方式来思考:

1、分析新增功能的边界和范围,和现有功能的关系;

2、结合现有功能和新增的部分,看是否需要提取接口、类是否需要拆分、方法是否需要合并、参数是否需要扩展;

3、整理出第一版设计后,就开始进行编码,过程中发现问题及时调整重构;

4、在不断优化过程中,会慢慢发现,最后的代码就符合某种模式了,所以说设计模式不是去生搬硬套,而是按照面向对象的设计原则逐步优化出来的。

现在所说的设计模式是基于面向对象语言,在面向对象语言中有很多的设计原则,在学习设计模式前需要了解并掌握这些设计原则,原则的灵活运用最终就体现成了各种模式,常用的原则有:

1、单一职责原则(SRP):一个类应该仅有一个引起它变化的原因;

2、开放封闭原则(OCP):类模块应该是可以扩展的,但是不可以修改(多扩展开放,对修改封闭);

3、Liskov 替换原则(LSP):子类必须能够替换他们的基类;

4、依赖倒置原则(DIP):高层模块不应该依赖于底层模块,二者都应该依赖于抽象;抽象不应该依赖于实现细节,实现细节应该依赖于抽象;

5、接口隔离原则(ISP):不应该强迫客户程序依赖于他们不用的方法;

6、迪米特法则(LOD):最小知识原则,类之间不该有直接关系的不要依赖,必须要有依赖关系的只依赖必要的抽象类或接口。

而到具体模式的学习就不得不提 GoF 23 种设计模式,这些设计模式在历史性的一本经典著作《设计模式:可复用面向对象软件的基础》中被描述的,这本书的四位作者并称为 Gang of Four(GoF) 。

现在市面上各种设计模式的书籍以及其他资料都是源于这 23 种,发展到今天模式已经远远不止 23 种,但我们只要学会了其根本就能够应对各种变化。

我们写代码时,引入任何的中间价、类库、权衡之下,肯定是利大于弊,我们才会使用,设计模式也是一样,如果只是盲目跟风,套用模式,会变成过度设计,得不偿失。初学者往往会犯这样的错误,觉得学习的模式得在项目中使用才行,找准时机就去套用。在学习过程中这样进行练习是可以的,但真实项目中,一定得去思考现在的方式有什么样的问题,为什么需要进行重构,然后才是思路和方法,得到最终的模式。

设计模式常常会按照创建型、结构型和行为型进行分类,其实很多模式并不常用、很多模式有很多的相似性。根据我自己的经验,我认为一个好的学习路径是:

1、先学习面向对象,然后掌握面向对象的设计原则;

2、学习常用的模式,多个模式可以对比起来学习;

3、搞懂模式能解决什么问题,和相似的模式应该怎么区分和选择;

4、结合实际的开发场景学习怎么应用;

5、阅读下 dotNET Core 源码,看看能不能发现使用了哪些设计模式。

后续的文章也大致会按照这个思路进行,不会按照常规的顺序、也不一定会每一个都介绍到,尽量做到最有价值的输出。

最后想说的是,程序员都应该学习设计模式,尤其是能养成一个使用设计思维的方式去处理问题更是一个程序员的必修课。