性价比学习设计模式

这篇博客来源于我在组内的一次分享,我做了一些删减,并添加了其它一些元素,让它看上去更像是一篇博客。
这里我并不打算把23种设计模式从前到后的细讲一遍,而是提供一种想法,一种思路,算是我自己对设计模式的理解。真的想理解好设计模式,还是应该看《GOF》

所以首先我会抛出一些我的结论并尝试逐一的解释它们。

设计模式有点“过时”了。

gof

那本被称为《GOF》的设计模式书,出版于1995年,而且书中大部分例子都围绕着桌面GUI开发,因为那是当年最火的模式,那我的理解,其实对于我一个做java后端开发的人来说,它其实有点过时了,比如里面类似“备忘录模式”,“命令模式”,“组合模式”这种,我可能一辈子都不会用到。再比如像是“迭代器模式”,“装饰器模式”这种,其实如今的语言已经默认都支持了。还有类似ioc控制反转这种,其实本身也可以算一种设计模式,但是因为理论和时间成熟相对较晚,并没有包含在GoF中,
所以也没必要在语言中,特别的去实现这一种模式了。总的来说,我想表达的一种思想就是:“只学习属于自己领域的那部分设计模式,其它的大概了解就行。”

放弃简单过于具体的模型,不要背类图,要从当时面临的问题思考设计模式。

你应该知道在学习设计模式的时候,有些类似《head first》,《大话设计模式》,这样的书籍,这些书籍看上去很好读,读起来很轻松很有趣,但是暴露一个严重的问题是,你只能大概听懂和了解这个模式是用来干嘛的,但是实际上你根本不知道怎么把它实践到具体的例子中。说简单点,根本没有什么地方,能让你写类似“飞机,大炮,坦克”的例子,你需要自己建立抽象思维来根据具体的场景,抽象出模型来。所以还是看原版的《GOF》好点,这本书首先会给你讲,到底我们在面临一个什么具体的case,然后针对这个case的设计模式是什么,在解决什么核心诉求,本质上来说,解决问题的场景,是设计模式的关键,如果你沉迷于背设计模式,背类图,那你会发现,很多设计模式的类图都差不多。

清晰的明白设计模式背后的思想:

划分好类的职责与边界。每个类只干好自己的事。

这个可以说是源于封装思想的基础,明确好每个类的职责,划分好边界。面向对象编程本身来说,就是一些对象的相互交互,本身就是对象与对象之间相互发送消息。所以设计一个对象,你要提供接口,限制类的访问权限,定义好类的协议。所以首先要符合最基本的建模思想,接下来再谈设计模式。

面向接口编程,把具体逻辑实现下沉到实现中。

简单的来说,就是面向接口编程,而不是面向实现编程,因为面向了接口编程,你可以让实现随意的被替换,这极大了增加的系统灵活性。不仅仅局限于对某个算法的实现细节下沉。还包括像创建者类的模式那样,把对象的创建,下沉到实现类中去。总之,设计模式总是看上去利用接口来做一个中间对象,从而实现了一个“缓冲区”,让你可以通过这个“缓冲区”间接地做很多事情。

少用继承,使用组合:

继承的好处是,子类可以从父类那里获得许多已经准备好了的属性和方法。但是缺点是,你仿佛是“强行”的获得了这些属性和方法。一点都不灵活。灵活的办法是使用组合的方式,来让这些可重用的部分,被你随意使用。甚至可以将实现同一接口的组件,进行随意替换。委托就是一个很好的例子,在重用和灵活扩展之间做了很好的协调。

23种设计模式串讲:

创建型模式

抽闲工厂模式:

抽象工厂的目的在于产品簇,一个产品簇的具体创建实现细节下沉到子类中去,但是它们都隶属于同一个产品簇,而不是简单的将对象的创建下沉到子类中去。

建造者模式:

建造者模式关键在一个具体复杂对象的构建过程已经确定,但是你可以根据需要来随意替换构建过程中,想要使用的组件,这在跨平台工具中非常常见的一种设计模式,比如在 Devexpress XAF这个工具中,你定义好了一个创建窗口的方式,就可以“一键生成”,多种不同平台的工具,他们可能是web项目,可能是win项目,平板电脑,甚至是app程序。但是却是同一份构建代码。

工厂方法:

工厂方法本身就是最基础的那种创建者模式思路,把一个对象的创建方式下沉到子类中去实现。

单例模式:

单例模式思想在于方便控制 一个类只有一个实例,其原理大概是,把构造函数私有化,并且通过锁,来控制访问并发。

原型模式:

原型模式可以通过拷贝的方式,创建一个新的对象,来减小创建对象的复杂性,其实这个模式没啥稀奇的。比如在java中,就是一个Cloneable接口。

过完创建者模式,顺便提一句,我现在在使用spring开发,几乎不怎么使用上面所列举出的工厂模式,因为依赖注入帮我做了大多数事。

结构型模式:

适配器模式:

适配器模式是在处理兼容工作中,很常用的模式,比如你在接手一个旧系统的时候,整个重构所经历的花销太大,为了保证新老并行,使用适配器来让这些不兼容的类可以一起工作,

桥接模式:

之前聊设计模式提到过,使用中间类,来让调用方和被调用方进行解耦,桥接模式相当于利用委托,做了两个中间类,来让双方都基于接口编程,都不相互依赖,python的WSGI就使用了这种模式。

组合模式:

组合模式将对象组合成树形结构以表示“部分-整体”的层次结构,使得用户对单个对象和组合对象的使用具有一致性。这明显是一个在GUI编程中常用到的模式。作为一名web开发者,不是很想深入的了解它。

装饰器模式:

我喜欢用一句自己的土话来描述装饰器模式。装饰器模式类似于在你执行一件事情(函数调用的时候)的前方做一些事儿,在后方做一些事儿。这个模式已经被融入到各个语言实现中去了,说白了就是AOP注解。

外观模式:

外观模式其实就是通过引入外观类的方式,来解耦系统内部的复杂调用和客户端使用方式。类似于大部分系统都会提供底层命令与高层命令。

享元模式:

享元模式是一种比较简单,比较底层的模式,利用共享技术来减少系统开销,简单来说,java的常量池就使用了享元模式。

代理模式:

代理模式通过中间对象来间接访问一个对象,从而在这个中间对象上做一些手脚,比如本地mock服务,智能指针。

如果仅仅的是看类图,会发现这几个模式的类图非常像。所以还是要从设计模式所要解决的问题场景入手,去理解设计模式。

行为型模式:

模板模式:

模板模式用来一系列的模板方法,让这些方法的实现下沉到子类,这是框架开发最常使用的设计模式。

策略模式:

策略模式的一个思路是将一个算法的具体实现,下沉到子类。

状态模式:

状态模式可以说利用了委托的技术,来让同一个类在不同状态下,表现出不同行为,这是一个在游戏编程中,很常见的设计模式。

观察者模式:

观察模式是主要思想就是“dont call me i will call you”,以注册通知回调的方式,来处理对象之间的变更依赖。 常用来实现事件处理系统。

备忘录模式:

这个模式让你的系统能够轻松的回到某个状态,其实更多的是类似绘图程序这种放弃修改,在web开发的使用中比较少。

中介者模式:

我在分享的时候,有个有趣的发现,就是有一部分同学,把代理模式和中介者模式混成一体,我觉得最根本的原因是,我们汉语常说代理中介,其实如果把他们翻译回英文,或者去思考它们所要解决的问题到底是啥,思路就会清晰很多,中介者模式其实在将对象的交互收口到中介者中,而不是散落在各处,不易维护。

迭代器模式:

迭代器模式其实针对早期使用for循环 i++的方式遍历元素不足的改进。然而这种模式已经被融入到语言实现中了。我们现在也不会特别的去实现一个迭代器模式了。

解释器模式:

当你的系统想要更加灵活的时候,最好的方式,就是嵌入一个解释器,来执行脚本。也就是设计一门领域语言。有一个说法是,你让你的代码变的越来越灵活,会发现他们越来越像一个解释器。

命令模式:

这个模式还是在GUI编程中,比较常见,就是针对动作建模,让一个动作支持撤销和重做。还支持宏。比如让你的鼠标右键和左上角编辑键的都支持复制。

责任链模式:

责任链模式最常见的使用场景,就是过滤器了。我们在spring或者其它一些web框架中也会配过滤器,如果符合过滤条件就直接返回,否则就处理给下一个过滤器去处理。

访问者模式:

访问者模式相当于对访问本身这个操作建模,有点类似迭代器模式,迭代器模式主要封装元素的迭代操作,访问模式对集合元素的封装操作更广泛。比如它可以使你在不改变各元素类的前提下定义作用于这些元素的新操作。