js 中常见的七设计模式

61 阅读2分钟

设计原则

    · 单一职责原则
        
    · 开放-封闭原则
        软件实体可以扩展但不可修改
    · 最少知识原则
        一个软件实体应当尽可能少的与其他实体发生相互作用

一、单例模式

    function Single(name){
        this.name = name;
    }
    
    Single.prototype.getName = function(){
        console.log(this.name);
    }
    
    function singleInstance(){
        let instance = null;
        
        return function(){
            if(!instance) {
                instance = new Single('贾贵')
            }
            
            return instance;
        }
    }

二、策略模式

    策略模式主要解决的是if-else 逻辑复杂而不可维护的情况
    
    如下代码,模拟一个公司发年终奖的情况
    
    const strategy = {
    
        s(base) {
            return base * 5;
        },
        
        a(base) {
            return base * 4;
        },
        
        b(base) {
            return base * 3;
        },
        
        c(base) {
            return base * 2;
        },
        
        d(base) {
            return base * 1;
        },
    }
    
    const getBouns = (base, grade) => strategy[base][grade];
    
    const res1 = getBouns(1000, 5) // 5000
    

三、装饰器模式

    在不改变自身的情况下,增加新的功能
    
    如下代码,创建3个plane
    plane1 可以发射子弹
    plane2 可以发射子弹和火箭弹
    plane3 可以发射子弹、火箭弹、导弹。
    
    function Plane1(){
        
    }
    
    Plane1.prototype.fire = function () {
        console.log('子弹')
    }
    
    function Plane2 (plane) {
        this.plane = plane;
    }
    
    Plane2.prototype.fire = function () {
        this.plane.fire();
        console.log('火箭弹');
    }
    
    function Plane3 (plane) {
        this.plane = plane;
    }
    
    Plane3.prototype.fire = function () {
        this.plane.fire();
        console.log('导弹')
    }
    
    let p1 = new Plane1();
    
    let p2 = new Plane2(p1);
    
    let p3 = new Plane3(p2);
    
    
    

四、订阅-发布者模式

    js中的事件就是经典的订阅发布者模式
    
    class Observer {
        constructor(){
            this.follows = [];
        }
        follow(obj){
            this.follow.push(obj)
        }
        publish(){
            this.follows.forEach(item => {
                item.fn(item.name);
            })
        }
    }
    
    
    

五、观察者模式

    // 定义主题,接受状态变化,并通知每一个观察者
    class Sub{
        constructor(){
            this.state = 0;
            this.observers = [];
        }
        
        // 获取状态
        getState(){
            return this.state;
        }
        // 设置状态
        setState(state){
            this.state = state;
            this.notify();
        }
        
        // 新增观察者
        addObserver(observer){
            this.observers.push(observer);
        }
        // 通知
        notify(){
            this.observers.forEach((item) => {
                item.update();
            })
        }
    }
    
    // 定义一个观察者
    class Obserer {
        constructor(name, sub) {
            this.name = name;
            this.sub = sub;
            this.sub.addObserver(this);
        }
        update(){
            console.log('更新了')
        }
    }
    
    let s = new Sub();
    let o = new Observer('李三', s);
    o.setState(2);
    

** 观察者模式和订阅发布者模式的区别:

    本质上的区别是调度的地方不同
    
    观察者模式是由具体目标调度的,而发布/订阅模式是统一由调度中心调的,
    
    所以观察者模式的订阅者与发布者之间是存在依赖的,而发布/订阅模式则不会。

**

六、迭代器模式

    遍历可迭代对象,就是一种迭代器模式
    
    如下代码,编写了一个倒叙遍历数组的函数
    
    const ary = [1,2,3,4,5,6];
    
    function reverseEcach (ary, callback) {
        if(ary.length === 0 ) return ;
        for(let index = ary.length - 1; index >= 0 ; index--) {
            callback(ary[index], index, ary);
        }
    }
    

七、代理模式

    主要用于转发请求
    
    如下代码模拟,发送邮件的过程。
    但是发送者不直接将邮件发送给接收者。而是通过将邮件交给邮递员,邮递员再将邮件发给接收者。
    
    // 创建邮件对象
        
    function Email(sender, content){
        this.sender = sender;
        this.content = content;
    }
    
    // 发布者
    
    const sender = {
        // target : 实际交给谁
        // receiver:最终的接收者
        // email:邮件
        send(target, receiver, email)
    }
    
    // 邮递员
    
    const postMan = {
        send(receiver, email){
            receiver.receive(email)
        };
    }
    
    // 实际接收者
    
    const receiver = {
        receive(email) {
            console.log('收到邮件')
        }
    }
    
    const email = new Email('Tom', 'hello world');
    
    sender.send(postMan, receiver, email);