创建型模式

工厂模式

在工厂模式中,我们在创建对象时不会对客户端暴露创建逻辑,并且是通过使用一个共同的接口来指向新创建的对象。

1
2
3
// 工厂模式创建对象
const objectFactory = (name,age)=>{ return {name,age} };
const myObject = objectFactory('张三',18);

抽象工厂模式

抽象工厂模式(Abstract Factory Pattern)提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。在抽象工厂模式中,接口是负责创建一个相关对象的工厂,不需要显式指定它们的类。每个生成的工厂都能按照工厂模式提供对象。
给工厂再抽象一层

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// 最顶层的抽象工厂
function AbstractFactory(factoryType){
if(AbstractFactory[factoryType]){
return AbstractFactory[factoryType]
}else{
throw new Error('没有当前类型的工厂')
}
}

// 具体的工厂1
AbstractFactory.childFactory1 = function(name){
return {name,type:'chidFactory1'}
}
// 具体的工厂2
AbstractFactory.childFactory2 = function(name){
return {name,type:'chidFactory2'}
}

let obj1 = AbstractFactory('childFactory1');
let obj2 = AbstractFactory('childFactory2');

原型模式

原型模式(Prototype Pattern)是用于创建重复的对象,同时又能保证性能。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。
这种模式是实现了一个原型接口,该接口用于创建当前对象的克隆。当直接创建对象的代价比较大时,则采用这种模式。例如,一个对象需要在一个高代价的数据库操作之后被创建。我们可以缓存该对象,在下一个请求时返回它的克隆,在需要的时候更新数据库,以此来减少数据库调用。

1
2
3
4
5
6
7
function Person(){
this.property.name = '张三';
this.property.say = function(){return this.name}
};

const zhangsan = new Person();
zhangsan.say();

单例模式

单例模式(Singleton Pattern)涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。
该模式的特点:
单例类只能有一个实例。
单例类必须自己创建自己的唯一实例。
单例类必须给所有其他对象提供这一实例。

1
2
3
4
5
6
7
8
9
10
11
12
13
let singleObject = null;

const createSingleObject = ()=>{
if(!singleObject)
{
signleObject = {//todo};
}
return singleObject;
}

let a = createSingleObject();
let b = createSingleObject();
// a===b true

结构型模式

桥接模式

桥接(Bridge)是用于把抽象化与实现化解耦,使得二者可以独立变化。这种模式涉及到一个作为桥接的接口,使得实体类的功能独立于接口实现类。这两种类型的类可被结构化改变而互不影响。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
class Color{
constructor(cl){this.color = cl};
draw(){ // todo }
}

class Speed{
constructor(v){this.v = v};
run(){//todo}
}

class Speak{
constructor(word){this.word = word};
say(){ //todo }
}

class Car(){
constructor(){
this.color = new Color('red');
this.speed = new Speed(10);
}
init(){
this.color.draw();
// todo
}
}
class Men(){
constructor(){
this.speed = new Speed(1);
this.speak = new Speak('hello');
}
init(){
this.speak.say();
// todo
}
}

const car = new Car();
const human = new Men();

外观模式

外观模式(Facade)为子系统中的一组接口提供了一个一致的界面,此模块定义了一个高层接口,这个接口值得这一子系统更加容易使用。
外观模式在JS中常常用于解决浏览器兼容性问题。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class BigObject{

func1(){
// TODO
}

func2(){
// TODO
}
// 提供简单方法给外部调用,忽略原本系统复杂性
simpleFunc(){
if(xx) { func1()}
else {
func2()
}
}
}

const obj = new BigObject();
obj.simpleFunc();

适配器模式

适配器模式(Adapter)是将一个类(对象)的接口(方法或属性)转化成客户希望的另外一个接口(方法或属性),适配器模式使得原本由于接口不兼容而不能一起工作的那些类(对象)可以一些工作。

1
2
3
4
5
6
7
8
9

function old2New(oldObj){
return {
newProperty:oldObj.oldProperty
}
}
var oldObj = {xxx}
// 使用old2New 转换对象结构
let newObj = old2New(oldObj)

代理模式

在代理模式(Proxy Pattern)中,一个类代表另一个类的功能。为其他对象提供一种代理以控制对这个对象的访问。

1
2
3
4
let obj ={}
// js 使用Proxy新特性创建代理
let proxyObj = new Proxy(obj,{})

行为型模式

观察者模式

观察者模式又叫发布订阅模式(Publish/Subscribe),它定义了一种一对多的关系,让多个观察者对象同时监听某一个主题对象,这个主题对象的状态发生变化时就会通知所有的观察者对象,使得它们能够自动更新自己。
使用观察者模式的好处:

  1. 支持简单的广播通信,自动通知所有已经订阅过的对象。
  2. 目标对象与观察者存在的是动态关联,增加了灵活性。
  3. 目标对象与观察者之间的抽象耦合关系能够单独扩展以及重用
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
let publisher = {
let _events=[];
// 添加订阅
addListen(func){
_events.push(fuc)
}
// 移除订阅
removeListen(func){
_events=_events.filter(x=>x!=func)
}
// 响应
run(){
_events.foreach(t=>t();)
}
}

let f1 = ()=>{//todo}
let f2 = ()=>{//todo}
// 加入订阅
publisher.addListen(f1);
publisher.addListen(f2);
// 发布者响应
publisher.run(); // f1();f2();

策略模式

策略模式的定义是:定义一系列的算法,把它们一个个封装起来,并且使它们可以相互替换。
优点:策略模式的使用,避免过多的 if…else… 判断,也可以替代简单逻辑的 switch。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 非策略模式
const func = (type){
if(type==0){return '000'}
else if(type==1){return '111'}
else if(type==2){return '222'}
}

// 策略模式
const func =(type){
const _types={
0:'000',
1:'111',
2:'222'
}
return _types[type]
}