开发成长之路(14)-- 设计模式:写代码的艺术_设计模式

前言

写完项目之后,再来看这个设计模式,就会觉得前面写的那些代码好垃圾啊,不知道是谁写出来的。
设计模式并不是书上那简单的23种,在真实的应用场景中可能会有不同的变种,以及多种模式的嵌套。
书上那些模式也有不少是互相变种出来的,所以我们重在思想,不要流于表面。

系列教程一览

开发成长之路(1)-- C语言从入门到开发(入门篇一)
开发成长之路(2)-- C语言从入门到开发(函数与定制输入输出控制函数)
开发成长之路(3)-- C语言从入门到开发(讲明白指针和引用,链表很难吗?)
开发成长之路(4)-- C语言从入门到开发(距离开发,还差这一篇)
开发成长之路(5)-- C语言从入门到开发(仿ATM机项目,我写的第一个项目)
开发成长之路(6)-- C++从入门到开发(C++入门不难)
开发成长之路(6)-- C++从入门到开发(C++知名库:STL入门·容器(一))
开发成长之路(7)-- C++从入门到开发(C++知名库:STL入门·容器(二))
开发成长之路(8)-- C++从入门到开发(C++知名库:STL入门·容器(三))
开发成长之路(9)-- C++从入门到开发(C++知名库:STL入门·空间配置器)
开发成长之路(10)-- C++从入门到开发(C++知名库:STL入门·算法)
开发成长之路(11)-- STL常用函数大集合
开发成长之路(12)-- Linux网络服务端编程(通识篇之熟悉操作环境)
开发成长之路(13)-- Linux网络服务端编程(通识篇)
开发成长之路(14)-- 小项目:视频点播器服务端(放码过来)


“看,未来”的个人简介

朋友们大家好,我是“看,未来”,最近跟CSDN头部大佬们学了这一招,听说挺受用的,我也来试试。

本系列主要面向想要走开发路线,又不知从何学起的大学生。
我本人也是在大一的时候就去参加了培训,后来又自学了一段时间,在这期间,我觉得更重要的是跟行业内的前辈们请教,这比培训来的实在多了。

网页右侧有我的个人微信二维码,如果对学习有困惑的小伙伴可以扫我,知无不言,言无不尽,欢迎来聊。

设计模式原则

单一职责原则:一个类只有一个职责。

优势:

  • 类的复杂性降低,实现什么职责都有明确的定义。 这是最首要的,如果不能降低复杂度,那就别分开
  • 可读性提高
  • 可维护性提高
  • 变更引起的风险降低

依赖倒置原则:

  • 高层模块不应该依赖于低层模块,二者都应该依赖于抽象。
  • 抽象不应该依赖于细节。
  • 细节应该依赖于抽象。

举个例子:松耦合、强内聚的电脑,是怎么组装的呢?
就拿CPU来说,CPU的对外都是针脚式或触点式的标准接口,只要接口设计好,内部再复杂和外界也没有关系。哪个主板要插CPU,那就得和CPU的接口对上。那么这时候如果电脑的内存条坏了,就不该成为你更换麦克风的理由。这不是开玩笑,要是收音机的外放坏了,可能得整部收音机脱胎换骨了。

PC的接口始终是有限的,但是软件设计得好,却可以不断地拓展的。

我们来思考一下依赖倒置对并行开发的影响。
如果两个类之间有依赖关系,只要定制出两者之间的接口(或抽象类),就可以独立开发了。

最佳实践:

依赖倒置原则的本质就是通过抽象使得各个类或模块的实现彼此独立,不互相影响,实现模块之间的松耦合,我们怎么在项目中使用这个规则呢?只要通过以下的几个规则:

  • 每个类尽量都有接口或抽象类,或者抽象和接口二者都具备。
  • 变量的表面类型尽量是接口或者抽象类。
  • 任何类都不应该从具体类派生。
  • 尽量不要覆写基类的方法。

接口隔离原则:

它建立在“依赖倒置原则”之上,
它的定义有俩:

  • Client should not be forced to depend upon interfaces that they don’t use.
  • 客户端不应该依赖于它不需要的接口。
  • The dependency of one class to another one should depend on the smallest possible interface.
  • 类之间的依赖关系应该建立在最小的接口上。

简单易懂啊,如果对前面那个原则有一定的把握。

建立单一接口,接口尽量细化。


什么是高内聚?高内聚就是提高接口、类、模块的处理能力,减少对外的交互。比如说你告诉你的保镖,今天去给我买一打爱马仕,他就去了。你也不用问他花了多少钱,他也不用问你是不是抽风了,这种不问条件执行的行为就是高内聚。
接口是对外的承诺,承诺越少对系统的开发越有利,变更的风险也越大,同时也有利于降低成本。


 - 一个接口只服务于一个子模块或业务逻辑
 - 通过业务逻辑压缩接口中的public方法,接口要勤快点重构
 - 已经被污染的接口,尽量去修改
 - 了解环境,拒绝盲从


开-闭原则:一个软件实体,应该对拓展开放,对修改关闭。

抽象实体:

项目或软件产品中按照一定的逻辑规则划分的模块。
抽象类
方法

这个原则很重要,后面会很经常见。
多说无益,我就稍微说两句,后面慢慢看它真面目。

如何应对需求变化?

既然说,对修改要关闭,那需求变化了怎么办?
有如下方法:

1、修改接口
2、修改实现类
3、通过拓展实现变化

类图

开发成长之路(14)-- 设计模式:写代码的艺术_设计模式_02

类图还是相对来说比较重要的,不过篇幅较长,我专门准备了一篇来放:
UML类图快速上手


单例模式

什么是单例模式呢?
在项目中,有些类是需要对它们进行“计划生育”的,即这个类只能有一个实例,如果出现多个实例则会有数据不一致的风险。

单例模式:保证一个类仅有一个实例,并提供一个访问它的全局访问点。

这个模式的类,叫单例类,所以类图我就不画了吧。
单例模式的应用场景举例:牵扯到数据问题,数据库首当其冲,缓存自然也跑不了。

应用场景及代码示例:
我用过的设计模式(2)-- 单例模式


观察者模式

什么是观察者模式呢?顾名思义,是一种触发机制。在电视里见过埋手雷不?某个倒霉蛋不小心扯到了手雷的线,轰的一声儿手雷炸了,倒霉蛋瞬间连渣都没得了。

这就是观察者模式,其中要素有:监视者、消息传递、响应者。
那根线就是监视者,消息传递方式为线拉动了手雷的保险栓,响应者为手雷,轰的一声就是它的响应。

应用场景及代码示例:
我用过的设计模式(3)-- 观察者模式


责任链模式

什么是责任链模式呢?我们来看个小故事:

最近给团队里的程序员们分了个等级,模仿着阿里的那套模式,将我们团队里人分为P6/P7/P8/P9/P10。
来活儿的时候呢,就这样分配,根据难度初步估计,分配给对应的等级的程序员去做,难度等级7级就给P7,8级就给P8。

但是这样会有个什么问题呢?其实也没啥问题,就是这好像不需要用类,直接在场景main里面放一堆的if来判断就好了。
那如果分配到当前等级的人他不收呢?那就得移交到下一个等级去,这要是用ifelse来判断,可想而知代码将会有多么的拥挤。
而且将本不属于场景类的任务强加到场景类之中,似乎也不合情理。

所以,我们采用这样一个方法:创建一个责任类,将各级程序员按等级排序,当有任务来临时,依次向后,如果能接那就接了,轮到最后还没人接,那就退了,默认没人接。

这,就是责任链模式。

应用场景及代码示例:
我用过的设计模式(4)-- 责任链模式


中介者模式

又叫调停者模式,但是我更喜欢中介者这个名字,因为一下就表达出这个设计的意图了。

用一个中介对象封装一系列对象交互,中介者使各对象不需要显示的相互作用,从而使其耦合松散,而且可以改变他们之间的交互。

开发成长之路(14)-- 设计模式:写代码的艺术_编程开发_03

应用场景及代码示例:
我用过的设计模式(5)-- 中介者模式


门面模式

要求一个子系统的外部与其内部的通信必须通过一个统一的对象进行。门面模式提供一个高层次的接口,使得子系统更易于使用。

优点:高内聚,松耦合。安全,不通过门面上提供的方法,休想访问模块内部。

我用过的设计模式(6)-- 门面模式


享元模式

享元模式(Flyweight Pattern):运用共享技术有效地支持大量细粒度对象的复用。系统只使用少量的对象,而这些对象都很相似,状态变化很小,可以实现对象的多次复用。由于 享元模式要求能够共享的对象必须是细粒度对象,因此它又称为轻量级模式,它是一种 对象结构型模式。

说到享元模式,第一个想到的应该就是池技术了,String常量池、数据库连接池、缓冲池、线程池等等都是享元模式的应用,所以说享元模式是池技术和池技术密不可分。

面向对象技术可以很好地解决一些灵活性或可扩展性问题,但在很多情况下需要在系统中增加类和对象的个数。当对象数量太多时,将导致运行代价过高,带来性能下降等问题。享元模式正是为解决这一类问题而诞生的。享元模式通过共享技术实现相同或相似对象的重用。

应用场景及代码示例:
我用过的设计模式(7)–享元模式


备忘录模式

我也曾写过一些需要保存临时数据的功能,但是写那些功能的时候是真的烦躁,因为我需要创建很多的对象,然后将数据一个一个塞进去,取出来的时候又要将数据一个一个进行输出,这让我感觉很不爽。不仅仅是工作量大,代码重复度又高,关键是有些数据,它明明应该是私有变量,就这样变成了公有变量,这让我很相当不满意,毕竟有谁会愿意把自己的美好回忆公开呢?

这时候我们就需要使用一些技巧,在不破坏封装性的前提下,将内部数据取出,存放,后期恢复。

应用场景及代码示例:
我用过的设计模式(9)-- 备忘录模式


原型模式

知道构造函数的人一般都知道,构造函数分为”深构造“和”浅构造“。如果不知道的话,也不用去别的地方找了,一般来说结果不会很满意,因为我找过了。

应用场景及代码示例:
用C++跟你聊聊“原型模式” (复制/拷贝构造函数)


如果觉得不够看,可以去看我的那个专栏。

看完之后,再思考一下我们写的项目,你品,你细品。
开发成长之路(14)-- 设计模式:写代码的艺术_设计模式_04