工厂模式

将创建对象的具体逻辑封装在⼀个函数中,创建后返回这个对象,那么这个函数就可以被视为⼀个⼯⼚。

// 简单⼯⼚模式:只需要⼀个正确的参数,就可以获取到你所需要的对象,⽤于⽣成实例
// 比如对象工厂,函数工厂
function Animal(opts) {
    var obj = new Object();
    obj.color = opts.color;
    obj.name = opts.name;
    obj.getInfo = function () {
        return "名称:" + obj.name + ", 颜⾊:" + obj.color;
    };
    return obj;
}
var cat = Animal({ name: "波斯猫", color: "⽩⾊" });

// ⼯⼚⽅法模式:本意是将实际创建对象的⼯作推迟到⼦类中,这样核⼼类就变成了抽象类,
// ⼯⼚⽅法只是⼀个实例化对象的⼯⼚,只做实例化对象这⼀件事情,⽤于⽣成实例
class User {
    constructor(name = "", viewPage = []) {
        if (new.target === User) {
            throw new Error("抽象类不能实例化!");
        }
        this.name = name;
        this.viewPage = viewPage;
    }
}
class UserFactory extends User {
    constructor(name, viewPage) {
        super(name, viewPage); // 调⽤⽗类的constructor(name, viewPage),继承⽗类的this对象
    }
}
// let user = new User(); // 不允许直接实例化
let userFactory = new UserFactory();

//抽象⼯⼚模式:并不直接⽣成实例,⽽是⽤于对产品类簇的创建
function getAbstractUserFactory(type) {
    switch (type) {
        case "wechat":
            return UserOfWechat;
            break;
        case "qq":
            return UserOfQq;
            break;
        case "weibo":
            return UserOfWeibo;
            break;
        default:
            throw new Error("参数错误, 可选参数:wechat、qq、weibo");
    }
}
let WechatUserClass = getAbstractUserFactory("wechat");
let QqUserClass = getAbstractUserFactory("qq");
let WeiboUserClass = getAbstractUserFactory("weibo");
let wechatUser = new WechatUserClass("微信⼩李");
let qqUser = new QqUserClass("QQ⼩李");
let weiboUser = new WeiboUserClass("微博⼩李");

单例模式

保证⼀个类仅有⼀个实例,并提供⼀个访问它的全局访问点。

class Singleton {
    static getInstance = (function () {
        let instance;
        return function () {
            if (!instance) {
                instance = new Singleton(...arguments);
            }
            return instance;
        };
    })();
    constructor(name) {
        this.name = name;
    }
}

let s1 = Singleton.getInstance("lisi");
console.log(s1.name); //lisi
let s2 = Singleton.getInstance("san");
console.log(s1.name); //lisi
console.log(s1 === s2); // true

观察者模式

定义了对象间⼀对多的依赖关系,当⽬标对象的状态发⽣改变时,所有依赖它的对象都会得到通知。

// ⽬标者类
class Subject {
    constructor() {
        this.observers = []; // 观察者列表
    }
    // 添加
    add(observer) {
        this.observers.push(observer);
    }
    // 删除
    remove(observer) {
        let idx = this.observers.findIndex((item) => item === observer);
        idx > -1 && this.observers.splice(idx, 1);
    }
    // 通知
    notify() {
        for (let observer of this.observers) {
            observer.update();
        }
    }
}
// 观察者类
class Observer {
    constructor(name) {
        this.name = name;
    }
    // ⽬标对象更新时触发的回调
    update() {
        console.log(`⽬标者通知我更新了,我是:${this.name}`);
    }
}
// 实例化⽬标者
let subject = new Subject();
// 实例化两个观察者
let obs1 = new Observer("前端开发者");
let obs2 = new Observer("后端开发者");
// 向⽬标者添加观察者
subject.add(obs1);
subject.add(obs2);
// ⽬标者通知更新
subject.notify();
// 输出:
// ⽬标者通知我更新了,我是前端开发者
// ⽬标者通知我更新了,我是后端开发者

发布订阅模式

实现了对象间多对多的依赖关系,通过事件中⼼管理多个事件。⽬标对象并不直接通知观察者,⽽是通过事件中⼼来派发通知。

// 事件中⼼
let pubSub = {
    list: {}, // {onwork:[fn1,fn2],offwork:[fn1,fn2],launch:[fn1,fn2]}
    subscribe: function (key, fn) {
        // 订阅
        if (!this.list[key]) {
            this.list[key] = [];
        }
        this.list[key].push(fn);
    },
    publish: function (key, ...arg) {
        // 发布
        for (let fn of this.list[key]) {
            fn.call(this, ...arg);
        }
    },
    unSubscribe: function (key, fn) {
        // 取消订阅
        let fnList = this.list[key];
        if (!fnList) return false;
        if (!fn) {
            // 不传⼊指定取消的订阅⽅法,则清空所有key下的订阅
            fnList && (fnList.length = 0);
        } else {
            fnList.forEach((item, index) => {
                if (item === fn) {
                    fnList.splice(index, 1);
                }
            });
        }
    },
};
// 订阅
pubSub.subscribe("onwork", (time) => {
    console.log(`上班了:${time}`);
});
pubSub.subscribe("offwork", (time) => {
    console.log(`下班了:${time}`);
});
pubSub.subscribe("launch", (time) => {
    console.log(`吃饭了:${time}`);
});
// 发布
pubSub.publish("onwork", "9:00:00");
pubSub.publish("offwork", "18:00:00");
pubSub.publish("launch", "12:00:00");
// 取消订阅
pubSub.unSubscribe("onwork");
pubSub.publish("onwork", "9:00:00");

适配器模式

适配器⽤来解决两个接⼝不兼容的情况,不需要改变已有的接⼝,通过包装⼀层的⽅式实现两个接⼝的正常协作。

// 已有的地图接⼝
var googleMap = {
    show: function () {
        console.log("开始渲染⾕歌地图");
    },
};
var baiduMap = {
    display: function () {
        console.log("开始渲染百度地图");
    },
};
// 已有的渲染接⼝
var renderMap = function (map) {
    if (map.show instanceof Function) {
        map.show();
    }
};

// 适配器
var baiduMapAdapter = {
    show: function () {
        return baiduMap.display();
    },
};
renderMap(googleMap); // 开始渲染⾕歌地图
renderMap(baiduMapAdapter); // 开始渲染百度地图

代理模式

不直接引⽤另⼀个对象,通过代理对象间接引用,起到中介的作⽤。

var obj = {};
var proxy = new Proxy(obj, {
    get: function (target, key, receiver) {
        console.log(`getting ${key}!`);
        return Reflect.get(target, key, receiver);
    },
    set: function (target, key, value, receiver) {
        console.log(`setting ${key}=${value}!`);
        return Reflect.set(target, key, value, receiver);
    },
});
proxy.count = 1;
proxy.count;

装饰模式

不改变已有的函数,给函数添加额外的功能,⽐如ES7中的装饰器。

参考

https://refactoringguru.cn/design-patterns/catalog

最后修改:2021 年 10 月 14 日
你的赞赏是我前进的动力