设计模式概略 + 常用设计模式
包括单例模式、策略模式、代理模式、发布订阅模式、命令模式、组合模式、装饰器模式、适配器模式

# 设计模式概略


# 什么是设计模式

定义:在软件设计过程中,针对特定问题的简洁而优雅的解决方案

# SOLID 五大设计原则

  • Single:单一职责原则
    • 一个程序只做好一件事
  • Open:开放封闭原则
    • 对扩展开放,对修改封闭
  • Liskov:里氏置换原则
    • 子类能覆盖父类,并能出现在父类出现的地方
  • Interface:接口独立原则
    • 保持接口的单一独立
  • Dependency:依赖导致原则
    • 使用方法只关注接口而不关注具体类的实现

# 为什么需要设计模式

  1. 易读性
    • 使用设计模式能够提升代码的可读性,提升后续开发效率
  2. 可扩展性
    • 使用设计模式对代码解耦,能很好地增强代码的易修改性和扩展性
  3. 复用性
    • 使用设计模式可以重用已有的解决方案,无需再重复相同工作
  4. 可靠性
    • 使用设计模式能够增加系统的健壮性,使代码编写真正工程化

# 常见设计模式


# 单例模式

定义:唯一 & 全局访问。保证一个类仅有一个实例,并提供一个访问它的全局访问点。

应用场景: 能被缓存的内容,例如登陆弹窗。

# 策略模式

定义:定义一系列的算法,把他们一个个封装起来,并且使他们可以相互替换。把看似毫无联系的代码提取封装、复用,使之更容易被理解和扩展。

应用场景:要完成一件事情,有不同的策略。例如绩效计算、表单验证规则。

示例:

使用前
// 策略
const calculateBonus = (level, salary) => {
    switch (level) {
        case 's ': {
            return salary * 4;
        }
        case 'a': {
            return salary * 3;
        }
        case 'b': {
            return salary * 2;
        }
        default: { return 0; }
    }
    return strategies[level](salary);
};
calculateBonus("s", 20000); // 80000
calculateBonus("a", 10000); // 30000
使用后
// 策略
const strategies = {
    s: (salary) => {
        return salary * 4;
    },
    a: (salary) => {
        return salary * 3;
    },
    b: (salary) => {
        return salary * 2;
    },
};
const calculateBonus = (level, salary) => {
    return strategies[level](salary);
};
calculateBonus("s", 20000); // 80000
calculateBonus("a", 10000); // 30000

# 代理模式

定义:为一个对象提供一个代用品或占位符,以便控制对它的访问。替身对象可对请求预先进行处理,再决定是否转交给本体对象。

应用场景:当我们不方便直接访问某个对象时,或不满足需求时,可考虑使用一个替身对象来控制该对象的访问。

示例:

使用前
// 原生函数
const rawImage = (() => {
    const imgNode = document.createElement("img");
    document.body.appendChild(imgNode);
    return {
        setSrc: (src) => {
            imgNode.src = "./loading.gif";
            const img = new Image();
            img.src = src;
            img.onload = () => {
                imgNode.src = this.src;
            }
        },
    };
})();
rawImage.setSrc("http://xxx.gif");
使用后
// 原生函数
const rawImage = (() => {
    const imgNode = document.createElement("img");
    document.body.appendChild(imgNode);
    return {
        setSrc: (src) => {
            imgNode.src = src;
        },
    };
})();
// 代理函数
const proxyImage = (() => {
    const img = new Image();
    img.onload = () => {
        rawImage.setSrc(this.src);
    };
    return {
        setSrc: (src) => {
            rawImage.setSrc("./loading.gif");
            img.src = src;
        },
    };
})();
proxyImage.setSrc("http: //xxx.gif");

# 发布订阅模式

定义:对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都将得到通知。

应用场景:DOM 事件、消息通知

示例:

class PubSub {
    constructor() {
        this.subscribers = {};
    }
    // 订阅
    subscribe(type, fn) {
        let listeners = this.subscribers[type] || [];
        listeners.push(fn);
    }
    // 取消订阅
    unsubscribe(type, fn) {
        let listeners = this.subscribers[type];
        if (!listeners || !listeners.length) return;
        this.subscribers[type] = listeners.filter((v) => v !== fn);
    }
    // 触发订阅事件
    publish(type, ...args) {
        let listeners = this.subscribers[type];
        if (!listeners || !listeners.length) return;
        listeners.forEach((fn) => fn(...args));
    }
}
let ob = new PubSub();
ob.subscribe("add", (val) => console.log(val));
ob.publish("add", 1);

# 命令模式

定义:执行某些特定事情的指令

应用场景:富文本编辑器工具栏

示例:

// 设置命令
const setCommand = (button, command) => {
    button.onclick = () => {
        command.execute();
    };
};
// 业务逻辑
const MenuBar = {
    refresh: () => {
        console.log("refresh");
    },
};
const RefreshCommand = (receiver) => {
    return {
        execute: () => {
            receiver.refresh();
        },
    };
};
const refreshMenuBarCommand = RefreshCommand(MenuBar);
// 绑定按钮和命令
setCommand(refreshButton, refreshMenuBarCommand);

# 组合模式

定义:用小的子对象来构建更大的对象,将对象组合成树形结构,以表示 “部分 - 整体” 的层次结构。

应用场景:从 is-a 到 has-a

示例:

class MacroCommand {
    constructor() {
        this.commands = [];
    }
    // 添加子对象逻辑
    add(command) {
        console.log(this);
        this.commands.push(command);
    }
    // 执行父对象逻辑
    execute() {
        for (let i = 0; i < this.commands.length; i++) {
            this.commands[i].execute();
        }
    }
}
const macroCommand = MacroCommand();
const openCommand = {
    execute: () => {
        console.log('open ');
    }
}
const closeCommand = {
    execute: () => {
        console.log('close');
    }
}
macroCommand.add(openCommand);
macroCommand.add(closeCommand);
macroCommand.execute();

# 装饰器模式

定义:能够在不改变对象自身的基础上,在程序运行期间给对象动态地添加职责

应用场景:数据上报、统计函数执行时间

示例:

使用前
const ajax = (type, url, param) => {
    console.log(param);
}
const getToken = () => {
    return 'Token';
}
ajax();
getToken();
使用后
// 添加职责
Function.prototype.before = function (beforeFn) {
    return (...rest) => {
        beforeFn.apply(this, rest);
        return this(...rest);
    };
};
let ajax = (type, url, param) => {
    console.log(param)
}
const getToken = () => {
    return 'Token'
}
ajax = ajax.before((type, url, param) => {
    param.token = getToken()
})

# 适配器模式

定义:解决两个软件实体间的接口不兼容问题,改变已有的接口,就能够使它们协同作用。

应用场景:接口不兼容的情况

示例:

使用前
const aMap = {
    show: () => {
        console.log('开始渲染地图A');
    }
};
const bMap = {
    display: () => {
        console.log('开始渲染地图B');
    }
};
const renderMap = (type) => {
    if (type === 'a') {
        aMap.show();
    } else if (type === 'b') {
        bMap.display();
    }
};
使用后
const aMap = {
    show: () => {
        console.log('开始渲染地图A');
    }
};
const bMap = {
    display: () => {
        console.log('开始渲染地图B');
    }
};
// 适配层
const bMapAdapter = {
    show: () => {
        return bMap.display();
    }
};
const renderMap = (map) => {
    if (map.show instanceof Function) {
        map.show();
    }
};
renderMap(aMap);
renderMap(bAdapter);

参考:
字节青训营课程

更新于 阅读次数

请我喝[茶]~( ̄▽ ̄)~*

TagBug 微信支付

微信支付

TagBug 支付宝

支付宝