JavaScript中的设计模式

37 阅读3分钟

大家好,我是右子。

设计模式千千万,一个不中接着换。

我们在这里看一下JS中的都有那些设计模式吧。

什么是设计模式

设计模式是解决问题的一种思想,和语言无关。在面向对象软件设计的工程中,针对特定的问题简洁优雅的一种解决方案。

通俗一点的说,设计模式就是符合某种场景下某个问题的解决方案,通过设计模式可以增加代码的可重用性,可扩展性,可维护性,使得我们的代码高内聚、低耦合。

构造器模式

function Foo(name,age){
    this.name = name;
    this.age = age;
    this.say = function(){
        console.log(this.name,this.age);
    }
};
let fn = new Foo("小明",18);
fn.say(); // 小明 18

优点:

  • 构造器模式,可以充分复用代码。

缺点:

  • 每次new之后,方法内的属性都会重新申请内存空间,应该把可公共的提取到原型中。

原型模式

function Foo(name,age){
    this.name = name;
    this.age = age;
};
Foo.prototype.say = function(){
    console.log(this.name,this.age);
};
let fn = new Foo("小明",18);
fn.say(); // 小明 18

优点:

  • 工厂模式,可以将可复用的属性或方法放到原型中,减少内存占用。

原型模式我们还可以用ES6推出的Class写法,更简洁方便,它是构造器模式和原型模式的集合体。

Class Foo{
    constructor(name,age){
        this.name = name;
        this.age = age;
    }
    // 方法会被添加到prototype中,并且是不可枚举的。
    say(){
        console.log(this.name,this.age);
    }
};

let fn = new Foo("小明",18);
fn.say(); // 小明 18

Class的写法也可以用函数实现,这里已经了解的小伙伴可以跳过~

Class的规范要求:

  1. 要求严格模式
  2. 只能通过new来调用
  3. 函数不可枚举
  4. 方法本身不能使用new
"use strict";

function Foo(name,age){
    if( !(this instanceof Foo) ){
        throw new TypeError("必须通过构造函数new才能调用!");
    }
    this.name = name;
    this.age = age;
};

Object.defineProperty(Foo.prototype,"say",{
    value(){
        if( !(this instanceof Foo) ){
            throw new TypeError("不可通过new调用!");
        }
        console.log(this.name,this.age);
    },
    enumerable: false
});

工厂模式

  • 工厂模式决定创建对象类的实例,主要用来创建同一类的对象。
Class Factory{
    constructor(role,page){
        this.role = role;
        this.page = page;
    }
    static purview(role){
        switch(role){
            case "superamin":
                return new Factory("supermain",["home","detail"]);
            break;
            case "editor":
                return new Factory("editor",["detail"]);
            break;
            default: 
                return throw Error("传入的参数不正确");
        }
    }
}

Factory.purview("superamin");

优点:

  • 通过工厂模式,我们可以快速创建大量相似对象,没有重复代码。

策略模式

  • 定义一系列算法,并将算法封装起来,使他们可以相互替换。
let list = {
    "admin": ["home","detail"],
    "editor": ["detail"]
};
Class Foo{
    constructor(data){
        this.list = data;
    }
    bound(role){
        return this.list[role];
    }
}
let fn = new Foo(list);
fn.bound("admin") // ["home","detail"]

优点:

  • 具有易维护,易扩展的特点。
  • 避免多重if else的判断,解决代码编写复杂性。

观察者模式

  • 观察者模式有观察目标、观察者两类对象。
  • 观察目标可以添加多个观察者。
  • 目标发生状态变更,所有观察者都会接到通知。
class Subject{
    constructor(){
        this.obs = [];
    }
    // 绑定/添加
    add(){
        this.obs = this.obs.push(ob);
    }
    // 删除
    remove(ob){
        this.obs = this.obs.filter(item=> item!==ob);
    }
    // 通知
    notify(){
        this.ob.forEach(item=>{
            item.update();
        });
    }
} 
class Observer{
    constructor(){
    }
    update(){
        console.log("更新");
    }
}

const serve1 = new Observer();
const serve2 = new Observer();
const sub = new Sub();
sub.add(serve1);
sub.add(serve2);
// 2秒后通知所有观察者
setTimeout(()=>{
    sub.notify();
},2000);

优点:

  • 目标与观察者功能耦合度降低,专注自身功能逻辑;

缺点:

  • 对事件通知不能进行细分管控。

发布订阅模式

  • 发布者和订阅者不用互相通知,通过“第三方”实现调度,属于经过解耦的观察者模式。
class PubSub{
    constructor(){
        this.msgs = {};
    }
    publish(key,data){
        this.msg[key] && this.msg[key].forEach(item=> {
            if(typeof item==="function"){
                item(data);
            }
        });
    }
    subscribe(key,cb){
        if(!this.msgs[key]){
            this.msgs = [cb];
        }else{
            this.msgs.push(cb);
        }
    }
    unsubscribe(key,cb){
        if(!this.msg[key]){
            return
        }
        // 清除所有
        if(!cb){
            this.msg[key].length = 0;
        }else{
            this.msg[key] = this.msg[key].filter(item=> item!===cb);
        }
    }
}

优点:

  • 可以对事件通知,进行细分管控。