大家可以把自己的项目或者是代码理解成我们就是在编写模块,并且设计它们之间的沟通。其实一个项目或者功能我们都可以理解成它们就是通过模块和模块之间的互相沟通来完成的。所以说设计模式,说白了就是在帮助我们更好的去设计模块,并且更好的组织它们之间的沟通。
在开始学习设计模式之前我们非常有必要先来认识一下设计原则,因为设计模式其实可以看做是设计原则的一个具体体现。
设计原则如下图所示:
开闭原则:开闭原则就是说我们的程序要对扩展开放,对修改关闭。我们的程序要留出给具体使用的时候扩展功能的接口,但是在具体使用的时候不能让它去修改我们的源码,也就是说让我们在具体的使用我们框架或程序的时候,我们能够不用修改源码来扩展功能,像jQuery、vue、react它们都留出了很多扩展接口,平常说的vue插件,webpack插件都可以看成是一个开闭原则的体现。所以说我们平常在设计程序的时候,要留出一个给具体使用时扩展的接口,但是我们要封装自己的代码,不能让外部去修改。
单一职责原则:单一职责原则对我们设计程序非常有指导意义,它的意思就是说我们的一个模块只做一件事情,模块的工作越单一越好。
依赖倒置原则:依赖倒置原则的核心思想是上层模块不要依赖于具体的下层模块,而应该依赖于抽象,例如:我们的食物有很多种,但我们往往会选择餐厅作为我们吃东西的依赖,而不是选择具体的食物来作为吃东西的依赖。举例:
假设我们有四种食物,分别是food1、food2、food3、food4,然后在点餐的时候我们有一个order类,我们可以通过order这个类点餐,现在的问题在于order这个类它要具体依赖于食物还是依赖于什么?
先看反面演示,如果把order类(点餐)直接依赖于具体的食物,那么对于不同的食物我们就要设置不同的点餐方法(orderFood1、orderFood2、orderFood3…),如果有四种食物我们就需要在order类的prototype上面放上四个方法,如果食物很多就要写很多点餐方法,显然这样会产生很多问题。比如我们依赖具体的食物,一旦我们具体的食物发生了变动,对应的点餐方法也要发生变动,新增了食物或减少了食物点餐的方法也要去新增或减少。
要保证具体所使用的上层接口不会被下层接口的剧烈变动影响到,通常的做法就是在上层和下层之间加一层抽象层,所以我们可以不要让它依赖具体的食物,而是抽象出一个餐馆层,然后让我们的点餐类只依赖于这个抽象餐馆层而不是依赖于具体的某一个食物。
这个时候,为了避免下层这些具体的食物的变动会影响到具体点餐时点餐方法的变动,我们新增一个resturn函数作为中间层也就是餐馆层,餐馆层接收对应的食物名,然后新建一个list作为菜单,根据接收到的食物名返回对应的食物出去。
此时上层的点餐接口也就是order可以改变一下,接收食物名然后返回餐馆层对应的食物
这样下层的食物层无论怎么变动都不会影响到具体使用的order层,只需要去改变抽象层也就是餐馆层就可以了,这就是依赖倒置原则。
接口隔离原则:接口应该细化,功能应该单一,不要一个接口调用太多的方法,而是应该尽量的细化接口使其能力单一。它有点像单一职责原则,但它们的关注点不同,单一职责原则主要关注于模块本身,接口隔离原则主要关注于接口
迪米特法则:迪米特法则也叫最少知识原则,它的意义是如果我们让两个对象产生沟通,那么最好是让两个对象之间互相了解的越少越好,对象之间要产生沟通没有必要彼此非常了解。这个思想在设计模式有个比较典型的体现就是中介者模式,中介者模式就是让两个对象之间不直接沟通,通过中介者转达需求。
里氏替换原则:里氏替换原则主要关注于继承,它的意义是我们任何父类使用的地方,都可以使用子类去替换,说白了就是子类去继承父类的时候,子类必须保证完全继承父类的任何属性和方法,这样父类使用的地方能够使用子类进行替换。
以上六大设计原则是我们开发时的指导思想,设计模式是设计原则的具体体现,在学习设计模式的时候就可以体会到这一点。
我们的各种设计模式可以分为四大类
创建型:设计模式大家可以看成就是帮助和指导我们怎么去创建对象、怎么去创建模块以及怎么去设计模块之间的沟通,创建型的目的就是帮助我们更优雅的创建对象
结构型:帮助我们更优雅的设计整体以及局部的代码结构
行为型:它是模块间的行为模式总结,目的是帮助我们组织模块的行为,组织它们之间怎么互相沟通来达成功能目标
技巧型:帮助我们优化代码
工厂模式-大量创建对象:工厂模式相当于建造一个创建对象的工厂,然后告诉工厂我们需要什么对象,工厂就把对象返回给我们,工厂模式适用于大量创建对象的场景。
单例模式-全局只能有我一个:单例模式意思是我们需要如何设计代码,保证全局某一个特定的实例化对象只能有一个。
建造者模式-精细化组合对象:建造者模式适用于创建一个复杂的对象,其实就是精细化组合一个对象。
原型模式-JavaScript的灵魂:原型模式相当于原型链,它的意义是通过定义原型,后面创建的对象都依赖这个原型。(也叫委托模式,是将属性和方法等行为委托给父级来实现的设计模式)
通过以上四个设计模式可以看出创建型设计模式都是指导我们如何去创建对象。
外观模式-给你一个套餐:外观模式就像我们去餐厅点一个套餐,我们不用关心具体要求点什么菜,只需要点具体的套餐就行了,对于代码就是说我们把接口细化之后可以给调用者一个套餐,而不是让他关心具体应该使用哪一个接口。
享元模式-共享来减少数量:享元模式的目的主要是为了减少对象或者代码块的数量,当存在大量重复的对象或代码块时,可以观察一下这些对象和代码块之间有哪些不同的地方,然后把不同的地方提取为一个公共的享元,通过这个公共的享元来减少对象或代码块的数量。
适配器模式-用适配代替更改:当存在两个对象之间接口、数据不适配的时候,我们不用去更改这两个对象,而是通过写一段适配代码把接口或者数据进行适配。
桥接模式-独立出来,然后再对接过去:桥接模式关注于减少代码的耦合度,它的做法是将代码中的一些东西独立出来,然后再组合回去,来减少代码之间的耦合度。
装饰者模式-更优雅的扩展需求:装饰者模式主要应对于当我们的方法不满足现在的需求时如何更优雅的去扩展这个方法。
通过以上五个设计模式可以看出结构型设计模式是帮助我们更优雅的设计整体以及局部的代码结构。
观察者模式-我作为第三方转发:观察者模式相当于定义一个第三方,模块间的沟通通过这个第三方来进行转发。
职责链模式-像生产线一样组织模块:职责链模式相当于把各个模块之间组织成一条生产线,这个模块完成了就把任务交到下一个模块继续包装,依次传递。
状态模式-用状态代替判断:状态模式主张用状态代替判断,可以非常有效的减少if else分支,能够让对象根据不同的状态来展现不同的行为。
命令模式-用命令去解耦:命令模式指导我们用命令去解除执行者与命令者之间的耦合,我们无需关心执行者具体是谁、他要做什么,我们只需要给执行者一道命令执行者就会去执行。
策略模式-算法工厂:策略模式和状态模式有点类似,但是策略模式可以理解为一个算法工厂,告诉它要什么算法,它就返回什么算法。
迭代器模式-告别for循环:迭代器模式就是我们在不去了解某一个对象内部的情况下能够有序的去遍历这个对象内部,例如ES6的forEach循环。
通过以上六个设计模式可以看出行为型设计模式目的是帮助我们组织模块的行为,组织它们之间怎么互相沟通来达成功能目标。
链模式-链式调用:如jQuery的链式调用。
惰性模式-我要搞机器学习:惰性模式说高大上点是搞机器学习,说白点是在第一次执行之后把执行状态记录下来。
委托模式-让别人代替你收快递:委托模式相当于收快递,把消息委托别人代收。
等待者模式-等你们都回来再吃饭:等待者模式适用于多种异步操作情况下,当我们发出一堆的异步操作之后,需要等待者模式帮助我们让这些异步操作都返回了再进行下一步操作。
数据访问模式-一个方便的数据管理器:数据访问模式就是说我们去建立一个数据管理器。
通过以上五个设计模式可以看出技巧型设计模式目的是帮助我们更好的优化代码。