Not commonly used设计模式

other不常用设计模式概述

  • 创建型:原型模式

  • 结构型:桥接模式、组合模式、享元模式

  • 行为型:策略模式、模板方法模式、职责链模式、命令模式、备忘录模式、中介者模式、访问者模式、解释器模式

原型模式-Prototype

Prototype模式-概念

  • clone自己,生成一个新对象

  • java 默认有 clone 接口,不用自己实现

  • JS 中的应用 - Object.create

Prototype模式-代码

// Object.create 用到了原型模式的思想
// 基于一个原型创建一个对象
const prototype = {
    getName: function() {
        return this.first + ' ' + this.last;
    },
    say: function() {
        console.log('hello');
    }
}

// 基于原型创建 x
let x = Object.create(prototype);
x.first = 'A';
x.last = 'B';
console.log(x.getName());
x.say();

// 基于原型创建 y
let x = Object.create(prototype);
x.first = 'C';
x.last = 'D';
console.log(x.getName());
x.say();

原型模式对比JS中的原型 prototype

  • prototype 可以理解为 ES6 class 的一种底层原理

  • 而class是实现面向对象的基础,并不是服务于某个模式

  • 若干年后 ES6 全面普及,大家可能会忽略掉 prototype

  • 但是 Object.create 却是会长久存在

桥接模式-Bridge

Bridge模式-概念

  • 用于把抽象化与实现化解耦

  • 使二者可以独立变化

Bridge模式-代码

class ColorShape {
    yellowCircle() {
        console.log('yellow circle');
    }
    redCircle() {
        console.log('red circle');
    }
    yellowTriangle() {
        console.log('yellow triangle');
    }
    redTriangle() {
        console.log('red triangle');
    }
}

// test
let cs = new ColorShape();
cs.yellowCircle();
cs.redCircle();
cs.yellowTriangle();
cs.redTriangle();
class Color {
    constructor(name) {
        this.name = name;
    }
}

class Shape {
    constructor(name, color) {
        this.name = name;
        this.color = color;
    }
    draw() {
        console.log(`${this.color.name} ${this.name}`)
    }
}

// test
let red = new Color('red');
let yellow = new Color('yellow');
let circle = new Shape('circle', red);
circle.draw();

let triangle = new Shape('triangle', yellow);
triangle.draw()

Bridge模式-设计原则验证

  • 抽象和实现分离,解耦
  • 符合开放封闭原则

组合模式-Composite

Composite模式-概念

  • 生成树形结构,表示“整体-部分”关系

  • 让整体和部分都具有一致的操作方式

Composite模式-演示

  • 虚拟 DOM 中的 vnode 是这种形式,但是数据类型简单

  • 用 JS实现一个菜单,不算经典应用,与业务相关

Composite模式-代码

虚拟DOM

<div id="div1" class="container">
    <p><123/p>
    <p>456</p>
</div>

{
    tag: 'div',
    attr: {
        id: 'div1',
        className: 'container'
    },
    children: [
        {
            tag: 'p',
            attr: {},
            chidren: ['123']
        },
        {
            tag: 'p',
            attr: {},
            chidren: ['456']
        },
    ]
}
  • 整体和单个节点的操作是一致的
  • 整体和单个节点的数据结构也保持一致

Composite模式-设计原则验证

  • 将整体和单个节点的操作抽象出来

  • 符合开放封闭原则

享元模式-Flyweight

Flyweight模式-概念

  • 共享内存(主要考虑内存,而非效率)

  • 相同的数据,共享使用

  • JS中未找到经典应用场景

Flyweight模式-代码

<!-- 无限下拉列表将事件代理到高层节点上 -->
<!-- 如果都绑定到<a>标签对内存开销太大 -->

<div id="div1">
    <a href="#">a1</a>
    <a href="#">a2</a>
    <a href="#">a3</a>
    <a href="#">a4</a>
    <!-- 无限下拉列表 -->
</div>

<script>
    var div1 = document.getElementById("div1");
    div1.addEventListener('click', function(e) {
        var target = e.target;
        if (target.nodeName === 'A') {
            alert(target.innerHTML)
        }
    })
</script>

Flyweight模式-设计原则验证

  • 将相同的部分抽象出来

  • 符合开放封闭原则

策略模式-Strategy

Strategy模式-概念

  • 不同策略分开处理

  • 避免出现大量 if…else… 或者 switch…case…

  • JS 中未找到经典应用场景

Strategy模式-代码

class User {
    constructor(type) {
        this.type = type;
    }
    buy() {
        if (this.type === 'ordinary') {
            console.log('普通用户购买');
        }else if (this.type === 'member') {
            console.log('会员用户购买');
        }else if (this.type === 'vip') {
            console.log('vip 用户购买');
        }
    }
}

// test

let u1 = new User('ordinary');
u1.buy()

let u2 = new User('member');
u2.buy()

let u3 = new User('vip');
u3.buy()

修改为以下的策略模式

class OrdinaryUser {
    buy() {
        console.log('普通用户购买');
    }
}
class MemberUser {
    buy() {
        console.log('会员用户购买');
    }
}
class VipUser {
    buy() {
        console.log('vip 用户购买');
    }
}

// test

let u1 = new OrdinaryUser();
u1.buy()

let u2 = new MemberUser();
u2.buy()

let u3 = new VipUser();
u3.buy()

Strategy模式-设计原则验证

  • 不同策略,分开处理,而不是混合在一起

  • 符合开放封闭原则

模板方法模式-Template Method

class Action {
    handle() {
        handle1()
        handle2()
        handle3()
    }
    handle1() {
        console.log('1')
    }
    handle2() {
        console.log('2')
    }
    handle3() {
        console.log('3')
    }
}

职责链模式-Chain of Responsibility

Chain of Responsibility-概念

  • 一步操作可能分为多个职责角色来完成
  • 把这些角色都分开,然后用一个链串起来
  • 将发起者和各个处理者进行隔离

Chain of Responsibility-演示代码

// 请假审批,需要组长审批、经理审批、最后总监审批
class Action {
    constructor(name) {
        this.name = name;
        this.nextAction = null;
    }
    setNextAction(action) {
        this.nextAction = action;
    }
    handle() {
        console.log(`${this.name} 审批`)
        if (this.nextAction != null) {
            this.nextAction.handle()
        }
    }
}

let a1 = new Action('组长')
let a2 = new Action('经理')
let a3 = new Action('总监')

a1.setNextAction(a2);
a2.setNextAction(a3);
a1.handle()
  • 职责链模式和业务结合较多,js中能联想到链式操作

  • jQuery 的链式操作,Promise.then 的链式操作

Chain of Responsibility-设计原则验证

  • 发起者与各个处理者进行隔离

  • 符合开放封闭原则

命令模式-Command

Command模式-概念

  • 执行命令时,发布者和执行者分开

  • 中间加入命令对象,作为中转站

Command模式-演示代码

// 触发者
class Invoker {
    constructor(command) {
        this.command = command;
    }
    invoke() {
        console.log('开始');
        this.command.cmd();
    }
}

// 命令者
class Command {
    constructor(receiver) {
        this.receiver = receiver;
    }
    cmd() {
        console.log('触发命令');
        this.receiver.exec();
    }
}

// 接收者
class Receiver {
    exec() {
        console.log('执行');
    }
}

// 士兵
let soldier = new Receiver();
// 小号手
let trumpeter = new Command(soldier);
// 将军
let general = new Invoker(trumpeter);

general.invoke()

Command模式-JS 中的应用

  • 网页富文本编辑器操作,浏览器封装了一个命令对象
  • document.execCommand(‘bold’);
  • document.execCommand(‘undo’);

Command模式-设计原则验证

  • 命令对象与执行对象分开,解耦
  • 符合开放封闭原则

备忘录模式-Memento

Memento模式-概念

  • 随时记录一个对象的状态变化
  • 随时可以恢复之前的某个状态(如撤销功能)
  • 未找到JS中经典应用,除了一些工具(如编辑器)

Memento模式-演示代码

// 备忘类
class Memento {
    constructor(content) {
        this.content = content;
    }
    getContent() {
        return this.content;
    }
}

// 备忘列表
class CareTaker {
    constructor() {
        this.list = [];
    }
    add(memento) {
        this.list.push(memento)
    }
    get(index) {
        return this.list[index]
    }
}

// 编辑器
class Editor {
    constructor() {
        this.content = null;
    }
    setContent(content) {
        this.content = content;
    }
    getContent() {
        return this.content
    }
    saveContentToMemento() {
        return new Memento(this.content)
    }
    getContentFromMementent(memento) {
        this.content = memento.getContent();
    }
}

// test
let editor = new Editor();
let careTaker = new CareTaker();
editor.setContent('111');
editor.setContent('222');
careTaker.add(editor.saveContentToMemento()); // 存储备忘录
editor.setContent('333');
careTaker.add(editor.saveContentToMemento()); // 存储备忘录
editor.setContent('444');

console.log(editor.getContent());
editor.getContentFromMementent(careTaker.get(1)) // 撤销
console.log(editor.getContent());
editor.getContentFromMementent(careTaker.get(0)) // 撤销
console.log(editor.getContent());

Memento模式-设计原则验证

  • 状态对象与使用者分开,解耦

  • 符合开放封闭原则

中介者模式-Mediator

Mediator模式-概念

  • 类似买房、租房时中介者

Mediator模式-演示代码

class Mediator {
    constructor(a, b) {
        this.a = a;
        this.b = b;
    }
    setA() {
        let number = this.b.number;
        this.a.setNumber(number * 100);
    }
    setB() {
        let number = this.a.number;
        this.b.setNumber(number / 100);
    }
}

class A {
    constructor() {
        this.number = 0
    }
    setNumber(num, m) {
        this.number = num;
        if (m) {
            m.setB()
        }
    }
}

class B {
    constructor() {
        this.number = 0
    }
    setNumber(num, m) {
        this.number = num;
        if (m) {
            m.setA()
        }
    }
}

let a = new A();
let b = new B();
let mediator = new Mediator(a,b);

a.setNumber(3,mediator);
mediator.setB();
console.log(b.number);

Mediator模式-设计原则验证

  • 将各关联对象通过中介者隔离

  • 符合开放封闭原则

访问者模式-Visitor

Visitor模式-概念

  • 将数据操作和数据结构进行分离

  • 使用场景极少

解释器模式-Interpreter

  • 描述语言语法如何定义,如何解释和编译

  • 用于专业场景,使用场景极少