Skip to content

创建性设计模式

工厂模式

用于创建实例,就像工厂一样,输出参数,得到实例结果。包含工厂和实例类两个核心概念。工厂类的产出都应该是相识,或者叫一类东西(注意这个概念)

js
// 实例类
function One() {
    this.content = 'one'
}
function Two() {
    this.content = 'two'
}
function Three() {
    this.content = 'three'
}

function createFactory(type) {  // 工厂
    switch(type) {
        case 'one': 
            return new One()
        case 'two': 
            return new Two()
        case 'three': 
            return new Three()
    }
}

// 或者类的方式
function CreateFactory(type) {  // 工厂
    switch(type) {
        case 'one': 
            return new One()
        case 'two': 
            return new Two()
        case 'three': 
            return new Three()
    }
}
const some = createFactory('two')  // 工厂创建实例

工厂方法模式

如果要新增一个Four类,工厂方法类需要新增一个类和修改工厂方法,而且有可能使用者不清楚createFactory 到底是一个类还是方法。需要引入安全类模式(见代码)。
工厂方法是指将类的创建过程流转到子类中执行,核心类就变成了抽象类,同时引入安全类模式。好处是新增类时只用改一个地方

js
CreateFactory.set = {
    One() {
        this.content = 'one'
    },
    Two() {
        this.content = 'two'
    },
    Three() {
        this.content = 'three'
    }
}
function CreateFactory(type) {  // 安全类实现
    if(this instanceOf CreateFactory) {
        return new CreateFactory.set[type]()  // new如果返回一个对象,将对象作为实例,如果返回undefined,当前的this作为实例
    } else {
        return new CreateFactory(type)
    }
}

抽象工厂模式

工厂模式用于创建示例,抽象工厂用于创建类。包含工厂类,工厂中的抽象类,产品类三个部分。 比如培训制造汽车的厂,这个厂可以培训出其他汽车厂,其他汽车厂可以造汽车,这样别人只要知道是某个培训厂出来的就知道车有什么特性。
总的来说就是通过工厂模式创建了抽象类,不是具体的产品。真正的产品都是这些抽象类的实现。

js
class AbstractFactory {
    constructor(subClass, type) {
        if(new.target === AbstractFactory) {
            throw new Error('抽象类不能实例化')
        }
        // 将某个产品的特性交给某个来学习的厂
        function F() {}
        F.prototype = new AbstractFactory.set[type]();
        subClass.prototype = new F();
        return subClass
    }

    // 保存了这个厂所有抽象类
    static set =  {
        Car: class Car {
            constructor() {
                this.model = 'car'
            }
            featureA() {
                throw new Error('制造car需要自行完成特性A')
            }
            featureB() {
                throw new Error('制造car需要自行完成特性B')
            }
        },
        Bus: class Bus {
            constructor() {
                this.model = 'Bus'
            }
            featureA() {
                throw new Error('制造Bus需要自行完成特性A')
            }
            featureB() {
                throw new Error('制造Bus需要自行完成特性B')
            }
        },
        Truck: class Truck {
            constructor() {
                this.model = 'Truck'
            }
            featureA() {
                throw new Error('制造Truck需要自行完成特性A')
            }
            featureB() {
                throw new Error('制造Truck需要自行完成特性B')
            }
        }
    }
}
// 现在有一家宝马厂,最开始不会造汽车,但是有一些基础的技术BMWBase,想学习造汽车
class BMWBase { }
const BMWCar = new AbstractFactory(BMWBase, 'Car');
const bmwCar = new BMWCar()

建造者模式

在创建一个实例过程中,对实例每个特性都使用单独实例来创建。

js
class Sex {
    constructor(sex) {
        this.sex = 
    }
}
class Age {
    constructor(age) {
        this.age = age
    }
}
class Name {
    constructor(name) {
        this.name = name;
    }
}

// 根据几个特性创建学生
class Student {
    constructor(name, age, sex) {
        if(name instanceOf Name || age instanceOf Age ||  sex instanceOf Sex ) {
            throw new Error('具体化实例')
        }
        this._name = name;
        this._age = age;
        this._sex= sex;
    }
}

单例模式

保证某个类只有唯一的实例,多次创建也只返回相同的实例

js
function Human(name) {
    if(Human._cache) {
        return Human._cache;
    }
    this.name = name;
    Human._cache = this;
}
const p1 = new Human('a')
const p2 = new Human('b')
console.log(p1 === p2)

上面的方式将实例缓存到类的静态属性上,也可能出现修改的场景,通过闭包的方式避免修改。

js
function Human(name) {
    this.name = name;
}
const createSingleInstanceClass = function(targetClass) {
    return (function() {
        let _cache
        return function(...args) {
            if(!_cache) {
                _cache = new targetClass(...args)
            }
            return _cache
        }
    })()
}

const HumanSingle = createSingleInstanceClass(Human)
const p1 = new HumanSingle('a')
const p2 = new HumanSingle('b')
console.log(p1 === p2)

结构性设计模式

外观模式

将复杂的子系统接口创建成高级的封装好的接口

适配器模式

将不同接口统一化,降低使用成本。前提是不同接口描述的功能是一类

代理模式

通过一个新的对象完全代理对就对象的操作,代理模式的核心是代理对象和被代理的对象保持接口的一致,当删除代理对象时,程序的基本功能正常。

js
class MyImage {
    constructor() {
        this.img = document.createElement('img')
        document.appendChild(img)
    }
    setSrc(src) {
        this.img.src = src
    }
}

function createImageProxy() {
    return class ProxyMyImage {
        constructor(src) {
            this.image = new Image
            this.myImage = new MyImage()
            this.image.onload = () => {
                myImage.setSrc(image)
            }
        }

        setSrc(src) {
            this.myImage.setSrc('default.jpg')
            this.image.src = src
        }
    }
}
js
// 实现一个代理请求的接口
function uploadFile(file) {
    console.log(file)
}

const uploadFileProxy = (function() {
    let cache = [];
    let timer = null;
    return function(id) {
        cache.push(id)
        if(!timer) {
            timer = setTimeout(() => {
                cache.forEach(file => upload(file))
                time = null;
                cache = [];
            }, 2000)
        }
    }
})()

uploadFileProxy('some')
uploadFile('some')   // 在接口使用上没有差别,当以后代理类不需要时,可以放心的替换

组合模式

包含抽象base类,container容器类(基于base),元素类(基于base),每个类可以嵌套其他类(item类不行),每个类有统一的接口。

享元模式

将一个类区分为内部状态和外部状态,内部状态是指多个对象都是相同,用于共享。外部状态是变化的,当需要一个对象,将内部状态和外部状态组合。本质上是时间换空间的操作。

行为性设计模式

模版模式

实现一个抽象父类,并定义执行的流程,子类依次实现步骤

js
class Base {
    constructor() {
        this.actionA();
        this.actionB();
        this.actionC();
    }
    actionA() {
        throw new Error('action A should define by sub')
    }
    actionB() {
        throw new Error('action B should define by sub')
    }
    actionC() {
        throw new Error('action C should define by sub')
    }
}

class Action extend Base {
    actionA() {}  // 依次重写
    actionB() {}
    actionC() {}
}

观察者模式

分为被观察者和观察对象、也有衍生出发布订阅模式。

js
class Watcher {
    // 观察一个对象
    watch(good) {
        good._watcher.push(this)
    }
    // 观察者回调
    run() {
        console.log('商品变少,接收到通知')
    }
}

class Good {
    _watchers = [];
    count = 10
    out() {
        this.count--;
        // 通知所有的watcher
        this._watchers.forEach(watcher => {
            watcher.run(this.count)
        })
    }
}
const watcher = new Watcher();
const good = new Good();
watcher.watch(good);  // 观察
good.out();

发布订阅和观察者模式区别是对于依赖的管理,观察者模式的依赖是被观察对象本身在管理(如果依赖管理稍微复杂,被观察对象本身也会变复杂),会带来一些和被观察对象无关的状态。发布订阅是将依赖的管理交给订阅中心,结构上更去耦合。

js
class Watcher {
    center = center
    // 观察一个对象
    watch() {
        this.center.sub(this)
    }
    // 观察者回调
    run() {
        console.log('商品变少,接收到通知')
    }
}

const center = (() => {
    const _watcher = [];
    return {
        sub(watcher) {
            _watcher.push(watcher)
        },
        publish(data) {
            _watcher.forEach(watcher => watcher.run(data))
        }
    }
})()

class Good {
    center = center;
    count = 10
    out() {
        this.count--;
        // 通知所有的watcher
        this.center.publish(this.count)
    }
}
const watcher = new Watcher();
const good = new Good();
watcher.watch();  // 观察
good.out();

命令模式

将接受者总是封装成命令类,请求总是和命令绑定从而执行命令,忽略接受者的差异。 命令核心就是命令类,接受者和请求者,请求者总是会执行命令类,命令类将请求转发给未来的接受者。

ts
abstract class BaseCommand {
    abstract execute() {}
}

class OrderCommand extends BaseCommand {
    constructor(receiver) {
        this.receiver = receiver
    }
    executed() {
        this.receiver();
    }
}

abstract class BaseAction {
    abstract command
    abstract addCommand() {}
    abstract action() {}
}

class MoveAction extends BaseAction {
    command = null
    addCommand(command) {
        this.command = command;
    }
    action() {
        this.command.execute();
    }
}

责任链模式

责任链模式是将一个大函数拆分成参数功能相似的区段。数据在区段之前流转,上一个处理函数不满足,流转到下一条,如果满足,责任链终止。就需要满足责任链的处理函数总是能满足当前函数所有的功能。 包含处理函数、责任链节点两个关键类。

ts
/**
 * 订单超过500的,打7折,
 * 订单在200~500之间,如果level是A,打8折,如果level是B,打8.5折。
 * 如果订单在200以下,并且有card,打9折,没有card原价。
 */
function originFn(order, level, hasCard) {
    if(order > 500) {
        return order * 0.7
    } 
    else if () {}
    else if () {}  // 如果if else,新增修改规则变麻烦
    ....
}

// 按照打折的维度拆分,固定参数为 order, level, hasCard
function order500(order) {
    return order * 0.7
}
function order200500(order, level) {
    if(level === A) {
        return order * 0.8
    } else {
        return order * 0.85
    }
}
function orderLess200(order, _, hasCard) {
    return order * 0.9
}
function orderNormal(order) {
    return order
}

abstract class ChainAbstract {
    fn
    nextChain
    abstract setNextChain() {}
    abstract startCurrentChain() {}
}

class Chain extends ChainAbstract {
    nextChain = null
    constructor(fn) {
        this.fn = fn;
    }
    setNextChain(chain) {
        this.nextChain = chain;
    }
    startCurrentChain(...args) {
        let ret = this.fn(...args)
        if(ret === 'next') {
            return this.nextChain && this.nextChain.startCurrentChain(...args)
        }
        return ret
    }
    startChainAsync(cb, ...args) {
        this.fn((ret) => {
            if(ret === 'next') {
                return this.nextChain && this.nextChain.startCurrentChain(cb, ...args)
            }
            return cb(ret)
        }, ...args)
    }
}

const chain500 = new Chain(order500)
const chain200500 = new Chain(order200500)
const chainLess200 = new Chain(orderLess200)
chain500.setNextChain(chain200500)
chain200500.setNextChain(chainLess200)

chain500.startCurrentChain(700, 'A', false)

中介模式

节点本身不做逻辑处理,将状态上传到中介方,又中介调度处理。这样节点不用关注其他节点,尽可能少的额外状态。

状态机模式

实体类、状态类,状态切换函数。

ts
abstract class LightStateAbstract {
    light: Light
    constructor(light) {
        this.light = light
    }
    abstract pressButton
}

class OnLightState extends LightStateAbstract {
    pressButton() {
        console.log('current is on, next is off')
        this.light.setState(this.light.off)
    }
}

class OffLightState extends LightStateAbstract {
    pressButton() {
        console.log('current is off, next is on')
        this.light.setState(this.light.on)
    }
}

class Light {
    constructor() {
        this.on = new OnLightState(this);
        this.off = new OffLightState(this);
        this.currentState = this.on;
    }
    setState(state: LightState) {
        this.currentState = state;
    }
    pressButton() {
        this.currentState.pressButton();
    }
}

const light = new Light();
light.pressButton();  // on
light.pressButton(); // off
light.pressButton(); // on

js中有基于FSM的状态机。实现逻辑差不多。

ts
const FSM = {
    on: {
        press() {
            console.log('on')
            this.currentState = this.off;
        }
    },
    off: {
        press() {
            console.log('off')
            this.currentState = this.on
        }
    }
}
const light = {
    on: FSM.on,
    off: FSM.off,
    currentState: FSM.,
    press() {
        this.currentState.press.call(this)
    }
}

基于闭包的状态机。上面状态都是手动声明,通过闭包来保存当前的状态

ts
function delegate(light, next) {
    return {
        press() {

        }
    }
}