自从读了《代码整洁之道-程序员的职业素养》后,闲人照计划找了几本有关设计模式的书去学习。今天闲人来总结下学到的东西。
感觉国内的书,翻译得都不太好让人吸收,常出现一些没有注释且难以理解的词句,不过还是要谢谢译者们的辛苦,让我这种英语水平低下的人,也有机会吸收更多知识。
模式列表
- 设计原则
- 常用设计模式24种
- 创建型模式5种
- 结构型模式7种
- 行为模式12种
- 解释器模式:将语言元素包含在应用程序中的方法,以匹配预期语言的语法
- 模版方法:在方法中创建算法的shell,然后将确切的步骤推到子类
- 职责链模式:在对象链之间传递请求的方法,以找到能够处理请求的对象
- 命令模式:将命令执行从其调用程序中分离的方法
- 迭代器模式:顺序访问一个集合中的元素,无需了解该集合的内部工作原理
- 中介者模式:在类之间定义简化的通信,以防止一组类显式引用彼此
- 备忘录模式:捕获对象的内部状态,以能够在以后恢复它
- 观察者模式:向多个类通知改变的方式,以确保类之间的一致性
- 状态模式:状态改变时,更改对象的行为
- 策略模式:在一个类中封装算法,将选择与实现分离
- 访问者模式:向类添加一个新的操作,无需改变类
- 空对象模式:向类添加一个新的操作,无需改变类
- 总结
设计原则
SOLID五大原则
注:SOLID 是由5个设计原则的英文首字母组成
单一责任原则
英文:Single Responsibility Principle
简写:SRP
说明:一个类或模块只负责一个功能领域中的相应职责
补充:是实现高内聚
、低耦合
的指导方针
开放/封闭原则
英文:Open/Closed Principle
简写:OCP
说明:软件实体应对扩展开放,而对修改关闭
补充:为了满足开闭原则,必须
对系统进行抽象设计
里氏代换原则
英文:Liskov Substitution Principle
简写:LSP
说明:所有引用基类对象的地方能够透明地使用其子类的对象
接口隔离原则
英文:Interface Segregation Principle
简写:ISP
说明:使用多个专门的接口,而不使用单一的总接口
依赖反转原则
英文:Dependency Inversion Principle
简写:DIP
说明:抽象不应该依赖于细节,细节应该依赖于抽象
补充:对抽象层
进行编程,而不对具体实现
进行编程
其它设计原则
迪米特法则
英文:Law of Demeter
简写:LOD
说明:一个软件实体应当尽可能少的与其他实体发生相互作用
补充: 别称最少知识原则
合成复用原则
英文:Composite Reuse Principle
简写:CRP
说明:尽量使用对象组合,而不是继承来达到复用的目的
不要重复原则
英文:Dont’t Repeat Yourself
简写:DRY
说明:同一个方法,在同一个系统中不要出现两次
补充: 该原则有一定局限性,主要用来提高代码质量。
常用设计模式24种
创建型模式5种
单例模式:一个类在全局访问点只有唯一一个实例
class World {
constructor(){
if(World.instance) return World.instance;
World.instance = this;
}
}
饿汉单例
:系统加载即初始化
懒汉单例
:对象在初次使用时进行初始化
多例模式
:是单例模式的衍生,一般用于对象池
const idleInstance = [];
const busyInstance = [];
class Pool {
constructor(){
if(idleInstance.length){
const instance = Pool.idleInstance.pop();
busyInstance.push(instance);
return instance;
}
if(busyInstance.length > 5) throw Error('无可用对象');
busyInstance.push(this);
}
workEnd(){
const index = busyInstance.indexOf(this);
if(index !== -1){
idleInstance.push(this);
busyInstance.splice(index, 1);
}
}
}
原型模式:用于复制或克隆完全初始化的实例
const prototype = { a: 1 };
function C(){};
C.prototype = prototype;
工厂方法:基于接口数据或事件生成几个派生类的一个实例
const GoodsFactorys = {};
class GoodsFactory {};
function addGoodsFactory(type, builder){
GoodsFactorys[type] = builder(GoodsFactory);
}
addGoodsFactory('Goods1', function(GoodsFactory){
return class Goods1 extends GoodsFactory {}
});
addGoodsFactory('Goods2', function(Factory){
return class Goods2 extends GoodsFactory {}
});
function getInstance(type, ...args){
const Goods = GoodsFactorys[type] || GoodsFactory;
return new Goods(...args);
}
简单工厂模式
:只能生成一个类的实例方法
注:所有单独存在的类都可以被称为简单工厂模式
抽象工厂:创建若干类系列的一个实例,无需详述具体的类
const ShopFactorys = {};
function ShopFactory(callback){
const GoodsFactorys = {};
class GoodsFactory {};
function addGoodsFactory(type, builder){
GoodsFactorys[type] = builder(GoodsFactory);
}
addGoodsFactory('Goods1', function(GoodsFactory){
return class Goods1 extends GoodsFactory {}
});
addGoodsFactory('Goods2', function(Factory){
return class Goods2 extends GoodsFactory {}
});
return function getInstance(type, ...args){
const Goods = GoodsFactorys[type] || GoodsFactory;
return new Goods(...args);
}
}
function addShopFactory(type, builder){
ShopFactorys[type] = builder(ShopFactory);
}
addShopFactory('Shop1', function(ShopFactory){
return ShopFactory(function(addGoodsFactory){
addGoodsFactory('Goods3', function(GoodsFactory){
return class Goods3 extends GoodsFactory {}
});
addGoodsFactory('Goods4', function(GoodsFactory){
return class Goods4 extends GoodsFactory {}
});
});
});
addShopFactory('Shop2', function(ShopFactory){
return ShopFactory(function(addGoodsFactory){
addGoodsFactory('Goods5', function(GoodsFactory){
return class Goods5 extends GoodsFactory {}
});
addGoodsFactory('Goods6', function(GoodsFactory){
return class Goods6 extends GoodsFactory {}
});
});
});
function getFactory(type){
return Factorys[type] || Factory;
}
注:抽象工厂也可以返回其它抽象工厂
生成器模式:从表示中分离对象构建,总是创建相同类型的对象
class Builder {
constructor(options){
this.buildStep1(options || {});
this.buildStep2(options || {});
this.buildStep3(options || {});
}
buildStep1(options){
this.type = options.type;
}
buildStep2(options){
this.name = options.name;
}
buildStep3(options){
Object.assign(this, options);
}
}
注:常把复杂对象的初始化方法拆分成多个步骤
结构型模式7种
适配器模式:匹配不同类的接口,因此类可以在不兼容接口的情况下共同工作
class Wrapper{
constructor(instance){
this.instance = instance;
}
async method(...args){
return Promise.resolve(this.instance.method(...args))
}
}
桥接模式:将对象接口从其实现中分离,因此它们可以对立进行变化
class Methods {
construtor(Bridge){
this.Bridge = Bridge;
}
method(){
console.log(this.Bridge.value)
}
}
组合模式:简单和复合对象的结构,使对象的总和不只是它各部分的总和
const people = new People();
const monkey = new Monkey();
const monkeyPeople = {
name: 'monkeyPeople',
run: People.prototype.run,
jump: Monkey.prototype.jump,
}
装饰器模式:向对象动态添加备选的处理
function Decorator(people){
const see = people.see;
people.see = function(target){
see.call(people, target);
if(target.name === 'sun'){
people.dead();
}
}
return people;
}
const people = Decorator(new People());
外观模式:隐藏整个子系统复杂性的唯一一个类
const people = new People();
function facade(){
people.see('mirror');
people.draw('eyebrow');
return people.face();
}
享元模式:运用共享技术来有效支持大量细粒度的对象
var shareData = {};
function usedShareData1(){
shareData.value = 1;
shareData.created = 1;
}
function usedShareData2(){
shareData.value = 2;
shareData.updated = 1;
}
代理模式:占位符对象代表真正的对象
function targetAccpet(fromSign){
if(fromSign === 0) throw Error('不接受该信息');
console.log('成功接受代理信息');
}
function agentAccpet(fromSign){
targetAccpet(1);
}
function sendToAgent(){
agentAccpet(0);
targetAccpet(0);
}
行为模式12种
解释器模式:将语言元素包含在应用程序中的方法,以匹配预期语言的语法
function PlusInterpreter(value){
const [left,right] = value.split('+');
if(isNaN(left) || isNaN(right)) throw Error('语法错误');
return left * 1 + right * 1;
}
模版方法:在方法中创建算法的shell,然后将确切的步骤推到子类
function PlusTemplate(left, right){
if(isNaN(left) || isNaN(right)) throw Error('语法错误');
return PlusInterpreter(left + '+' + right);
}
职责链模式:在对象链之间传递请求的方法,以找到能够处理请求的对象
function method1(options){
console.log('method1');
}
function methodAnother(options){
console.log('methodAnother');
}
function method(options){
switch(options.next){
case 'method1':
method1(options);
break;
default:
methodAnother(options);
}
}
命令模式:将命令执行从其调用程序中分离的方法
const Command = {
Set(key, _, value){
console.log('设置' + key + '为' + value);
}
execute(value){
const [cmd,...args] = value.split(/s+/);
if(!this[cmd]) throw Error('命令不存在');
this[cmd](...args);
}
}
Command.execute('Set ENV is local');
迭代器模式:顺序访问一个集合中的元素,无需了解该集合的内部工作原理
function map(obj,callback){
return Object.keys(obj).map((k,i)=>callback(obj[k],k,i));
}
中介者模式:在类之间定义简化的通信,以防止一组类显式引用彼此
let events = [];
function on(callback){
events.push(callback)
}
function emit(){
const copy = events;
events = [];
copy.forEach(fn=>fn());
}
备忘录模式:捕获对象的内部状态,以能够在以后恢复它
const source = { a: 1 };
const remark = JSON.stringify(source);
source.a = 2;
Object.assign(source, JSON.parse(remark));
观察者模式:向多个类通知改变的方式,以确保类之间的一致性
const objects = [];
function on(e){
objects.push(e);
}
function emit(key){
objects.forEach(e=>e[key]());
}
状态模式:状态改变时,更改对象的行为
let state = false;
function toggle(){
state = !state;
}
策略模式:在一个类中封装算法,将选择与实现分离
function Strategy(options){
switch(options.type){
case 1:
return options.a1;
case 2:
return options.a2 + options.a3;
default:
return options.a;
}
}
访问者模式:向类添加一个新的操作,无需改变类
function entry(){
console.log(this.value);
}
entry.call({ value: 1 });
空对象模式:向类添加一个新的操作,无需改变类
function Run(object){
if(object !== null){
console.log(object);
}else{
console.log({ value: 'emptyObject' })
}
}
总结
闲人看了许多资料,各个资料对设计模式的理解都有出入,闲人认为,目前的设计模式,是针对面向对象语言的惯例,在针对JavaScript这种不是完全面向对象的语言来说,它并不是完全适用,有待后人整理出不同的,专用于JavaScript的设计模式来。闲人也会持续学习并更新所学的知识,希望对大家有所帮助。