设计模式

五大设计原则 SOLID

  • S 单一职责原则
  • O 开闭原则,对扩展开放,对修改关闭
  • L 里氏置换原则,子类覆盖父类
  • I 接口独立原则,迪米特法则,最少知识原则
  • D 依赖倒置原则,高层模块不应该依赖低层模块,两者都应该依赖其抽象

面向对象三要素

  • 继承 - 子类继承父类,复用性
  • 封装 - 数据的权限管理,减少耦合
  • 多态 - 同一接口的不同实现,保持子类的开放性和灵活性

面向对象的继承

  • public - 完全开放,子类和实例都可访问
  • protected - 仅子类可访问,实例不能访问
  • private - 仅该类内部可访问,子类和实例均不能访问
  • static - 仅能通过类名调用,子类和实例不能访问,可被继承,继承后可通过子类类名调用
  • abstract - 抽象类,用于抽象方法和属性,在类名和需要抽象的方法或属性前加 abstract 关键词,不能被实例化,子类中必须实现抽象的方法和属性

简单工厂模式

将 new 的操作进行单独封装

  • 示例

window.$()

React.creatElement()

  • 经典结构
class Product {
    fun1(){}
}

class Creator {
    create () {
        return new Product()
    }
}

const creator = new Creator()
const p1 = creator.create()
p1.fun1()
  • 优势

工厂函数内的构造函数发生变化时方便修改

单例模式

一个类只能有一个实例,并提供一个访问它的全局访问点。

  • 示例

window.$

vuex 和 redux

  • 经典结构
// js 通过闭包来模拟,注意不能 new 。懒汉式单例,在调用的时候实例化
class SingleObject {
    static getInstance = (() => {
        let instance;
        return () => {
            if (!instance) {
                instance = new SingleObject();
            }
            return instance;
        };
    })();
}

// 饿汉式单例,在类加载的时候就实例化
class SingleObject {
    static instance = new SingleObject();
    static getInstance = () => {
        return SingleObject.instance;
    };
}

const s1 = SingleObject.getInstance();
const s2 = SingleObject.getInstance();
console.log(s1 === s2); // true
// ts 版
class SingleObject {
    static instance: SingleObject;
    
    static instance() {
        if (!SingleObject.instance) {
            SingleObject.instance = new SingleObject();
        }
        return SingleObject.instance;
    }
}

const aa = SingleObject.instance();
const bb = SingleObject.instance();
console.log(aa === bb);

代理模式

为其他对象提供一种代理以控制对这个对象的访问。

装饰器模式

为 类/对象 添加新功能

- 适配器模式: 提供同一功能不同的接口

- 代理模式: 提供一模一样的接口

- 装饰器模式:原有功能不变且直接可用,扩展功能

外观模式

为子系统的一组接口提供一个高层接口

迭代器模式

顺序访问一个集合,把集合包装成一个迭代器,通过 next() 来顺序访问

观察者模式

// 发布-订阅模式
class Watcher {
    constructor  () {
        this.listeners = new Map()
    }
    emit (type, ...arg) {
        const events = this.listeners.get(type)
        if(events) {
            events.forEach(ev => ev(...arg))
        }
    }
    on (type, callback) {
        const events = this.listeners.get(type)
        if(events) {
            events.push(callback)
        } else {
            this.listeners.set([callback])
        }
    }
}
// 发布-订阅模式 TS 版
class Watcher {
    private m_lisneners: Map<string, ((...arg)=>void)[]>
    constructor () {
        this.m_lisneners = new Map()
    }

    on (name: string, event: (...arg)=>void) {
        const eventObj = this.m_lisneners.get(name)
        if (eventObj) {
            eventObj.push(event)
        } else {
            this.m_lisneners.set(name, [ event ])
        }
    }

    emit (name, ...arg) {
        const eventObj = this.m_lisneners.get(name)
        if (eventObj) {
            eventObj.forEach((callback: (...arg)=>void) => {
                callback(...arg)
            })
        }
    }
}

原型模式

clone 自己生成一个新对象,实例上提供 clone() 方法

例:Object.create

命令模式

将一个操作封装成对象,对操作进行排序并记录操作日志,并且操作可撤销。

建造者模式

将一个复杂对象的构建与它的表示分离,例如 absrtuct .

备忘录模式

在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。这样以后就可以将该对象恢复到之前保存的状态。