笔记-JS设计模式

135 阅读4分钟

JavaScript设计模式笔记

一、设计原则(SOLID)

  • S-单一职责原则
    • 一个程序只做一件事
    • 拆分复杂功能、每个部分保存独立
  • O-开放封闭原则
    • 对扩展开放,对修改封闭
    • 增加需求时、扩展新代码、而非修改现有代码
  • L-李氏置换原则
    • 子类能够覆盖父类
    • 父类出现的地方子类就能出现
  • I-接口独立原则
    • 保持接口的单一独立,避免出现“胖接口”
  • D-依赖倒置原则
    • 面向接口编程,依赖于抽象而不依赖于具体
    • 使用方只关注接口而不关注具体类的实现

二、设计模式类型

  • 创建型
    • 工厂模式
      • 工厂方法模式
      • 抽象工厂模式
      • 创建者模式
    • 单例模式
    • 原型模式
  • 结构型
    • 适配器模式
    • 装饰器模式
    • 代理模式
    • 外观模式
    • 桥接模式
    • 组合模式
    • 享元模式
  • 行为型
    • 策略模式
    • 模板方法模式
    • 观察者模式
    • 迭代器模式
    • 职责链模式
    • 命令模式
    • 备忘录模式
    • 状态模式
    • 访问者模式
    • 中介者模式
    • 解释器模式

三、设计模式介绍

1、工厂模式
class Product{
    constructor(name) {
        this.name = name;
    }
    init(){
        alert('init')
    }
    fun1(){
        alert('fun1');
    }
    fun2(){
        alert('fun2')
    }
}
class Creator {
    constructor() {
    }
    creator(name) {
        return new Product(name)
    }
}
let  creator = new Creator();
let product =   creator.creator('creator');
product.init();
product.fun1();
2、单例模式
  • 登陆框
  • 购物车
class LoginFrom {
    constructor() {
        this.state = 'hide';
    }
    show(){
        if(this.state === 'show'){
            alert('show');
            return ;
        }
        this.state = 'show';
        console.log('登陆框显示成功')

    }
    hide(){
        if(this.state === 'hide'){
            alert('hide');
            return ;
        }
        this.state='hide';
        console.log('登陆框隐藏成功')
    }
}
LoginFrom.getInstance = (function () {
    let instance  = null;
    return function () {
        if(!instance){
            instance = new LoginFrom();
        }
        return instance;
    }
})();
let login1 = LoginFrom.getInstance();
login1.show();
login1.show();
let login2 = LoginFrom.getInstance();
login2.hide();
console.log(login1 ===login2) ; // true
2、适配器模式
  • 旧接口结构和使用者不兼容
  • 中间加一个适配转换接口
class Adapter{
    specificRequest(){
        return '德国标准插头';
    }
}
class Target {
    constructor() {
        this.adpter = new Adapter();
    }
    request(){
        let info = this.adpter.specificRequest();
        return `${info} -转换器-中国标准插头`
    }
}
let target = new Target();
let res = target.request();
console .log(res);
3、装饰器模式
  • 为对象添加新功能
  • 不改变其原有的结构和功能
class Circle {
    draw(){
        console.log('画圆');
    }
}
class Decorator {
    constructor(circle) {
        this.circle = circle;
    }
    draw(){  
        this.circle.draw();
        this.setRedBorder(circle)
    }
    setRedBorder(){
         console.log('设置红色边框')
    }
}
let circle = new Circle();
circle.draw();
let dec = new Decorator(circle);
dec.draw();
// es7 装饰器
@testDec
class Demo{
    constructor(){
    }
}
function testDec(target) {
    target.isDec = true;
}
alert(Demo.isDec)
//---------------------------------
@testDec(true)
class Demo{
    constructor(){ }
}
function testDec(isDec) {
     return function (target) {
         target.isDec = isDec;
     }
}
alert(Demo.isDec)

4、代理模式
  • 使用者无权访问目标对象
  • 中间加代理,通过代理做授权和控制
    • (科学上网,梯子)
    • (明星经纪人)
class ReadImg {
    constructor(fileName) {
        this.fileName  = fileName;
        this.loadFromDisk()
    }
    display(){
        console.log('display....'+this.fileName);
    }
    loadFromDisk(){
        console.log('loading...'+this.fileName);
    }
}
class ProxyImage {
        constructor(fileName) {
            this.realImg = new ReadImg(fileName)
        }
        display(){
            this.realImg.display();
        }
}

let proxyImg = new ProxyImage('a.png');
proxyImg.display();
let star = {
    name:'zhangss',
     age:25,
     phone:'star-1520000000',
 }
 let agent = new Proxy(star,{
     get:function (target,key) {
         if(key ==='phone'){
             return 'agent-1875241264'
         }
         if(key ==='price'){
             // 明星不报价,经纪人报价
             return 12;
         }
         return target[key];
     },
     set:function (target,key,value) {
        if(key==='customPrice'){
            if(value<10){
                throw  new Error('价格太低');
            }else{
                target[key] = value;
                return true;
            }
        }
     }
 });
console.log(agent.name);
console.log(agent.age);
console.log(agent.phone);
console.log(agent.price);
agent.customPrice = 15;
console.log('agent.customPrice',agent.customPrice);
agent.customPrice = 9 ;
5、外观模式
  • 为子系统中的一组接口提供了一个高层接口
  • 使用者使用这个高层接口
6、观察者模式
  • 发布&订阅
  • 一对多
class Subject{
    constructor() {
        this.state = 0 ;
        this.observers = [];
    }
    getState(){
        return this.state;
    }
    setState(state){
        this.state = state;
        this.notifyAllObservers();
    }
    notifyAllObservers(){
        this.observers.forEach(oberver=>{
            oberver.update();
        })
    }
    attach(observer){
        this.observers.push(observer)   ;
    }
}
class Observer {
    constructor(name,subject) {
        this.name  =name;
        this.subject = subject;
        this.subject.attach(this)
    }
    update(){
        console.log(`${this.name} update,state:${this.subject.getState()}`)
    }
}
let s = new Subject();
new Observer('01',s);
 new Observer('02',s);
 new Observer('03',s);
s.setState(1)
s.setState(2)
s.setState(3)
7、迭代器模式
  • 顺序访问一个集合
  • 使用者无需知道集合的内部结构
class Iterator {
    constructor(container) {
        this.list = container.list;
        this.index = 0 ;
    }
    next(){
        if(this.hasNext()){
            return this.list[this.index++];
        }
        return  null;
    }
    hasNext(){
        if(this.index>=this.list.length){
          return false;
        }
        return true;
    }
}
class Container{
    constructor(list) {
        this.list = list;
    }
    getIterator(){
        return new Iterator(this);
    }
}
let container = new Container([1,2,3,4,4,12]);
let iterator = container.getIterator();
while(iterator.hasNext()){
    console.log(iterator.next())
}

ES6 Iterator

  • ES6语法中,有序集合数据类型
    • Array
    • Map
    • Set
    • String
    • TypedArray
    • arguments
    • NodeList
  • 需要有一个统一的遍历接口来遍历所有数据类型(object不是有序集合,可用Map代替)
  • 以上数据类型都有[Symbol.iterator]属性
  • 属性值是一个函数,执行函数返回一个迭代器
  • 这个迭代器就有next方法可顺序迭代子元素
  • 可运行Array.prototype[Symbol.iterator]来测试
function each(data) {
    // //  带有遍历器特性的对象:data[Symbol.iterator]有值
    // for(let item of data){
    //     console.log(item)
    // }
    let iterator = data[Symbol.iterator]();
    let item = {done:false};
    while(!item.done){
        item= iterator.next();
        if(!item.done){
            console.log(item.value)
        }
    }
}
let arr = [1,2,3,4,5];
each(arr)
let m = new Map();
m.set('a',100);
m.set('b',200);
each(m)
8、状态模式
  • 一个对象有状态变化
  • 每次状态变化都会触发一个逻辑
  • 不能if…else 来控制
// 状态(红灯、路灯、黄灯)
class State{
    constructor(color) {
        this.color = color;
    }
    handle(context){
        console.log(`turn to ${this.color} light`);
        context.setState(this)
    }
}
// 主题
class Context{
    constructor(){
        this.state = null;
    }
    // 获取状态
    getState(){
        return this.state;
    }
    setState(state){
        this.state = state;
    }
}
let context = new Context();
let green = new State('绿灯');
let yellow = new State('黄灯');
let red = new State('红灯');
green.handle(context);
console.log(context.getState());
yellow.handle(context);
console.log(context.getState());
red.handle(context);
console.log(context.getState());
9、其他设置模式
1、原型模式
  • clone自己,生成一个新对象
  • java默认有clone接口,不用自己实现
  • js中Object.create
const protoType = {
    getName:function () {
        return this.first + ' ' + this.last;
    },
    say:function () {
     console.log('hello')
    }
}
let x = Object.create(protoType);
let y = Object.create(protoType)

x.first = 'a';
x.last = 'b';
console.log(x.getName());
console.log(x.say())


y.first = 'c';
y.last = 'd';
console.log(y.getName());
console.log(y.say())

console.log(x,y)

prototype

  • prototype 是es6中class底层原理
  • class是实现面向对象的基础、并不是服务某个模式
  • ES6全面普及,大家可能会忽略prototype
  • Object.create会长久保留
2、桥接模式
  • 用于把抽象化与实现话解耦
  • 使得二者可以独立变化
    • 绘图形
      • 绘形状类和绘颜色类分开实现。
3、组合模式
  • 生成树形结构、表示“整体-部分”关系
  • 让整体和部分都具有一致的操作方式
4、享元模式
  • 共享内存
  • 相同的数据、共享使用

5、策略模式

  • 不同策略分开处理
  • 避免使用if……else 或 switch……case

class User{
    constructor(type) {
        this.type = type;
    }
    buy(){
        if(this.type == 'oridinary'){
            console.log('普通用户');
        }else if(this.type ==='member'){
            console.log('会员用户');
        }else if(this.type =='vip'){
            console.log('vip 用户购买');
        }
    }
}
let user  = new User('oridinary');
user.buy();
let user2 = new User('member');
user2.buy();
let user3 = new User('vip');
user3.buy();

class OrdinaryUser{
    buy(){
        console.log('普通用户');
    }
}
class MemberUser{
    buy(){
        console.log('会员用户');
    }
}
class VipUser{
    buy(){
        console.log('vip');
    }
}

let u1 =new OrdinaryUser();
u1.buy();
let u2 = new  MemberUser();
u2.buy();
let u3 = new VipUser();
u3.buy();
5、模板方法模式
6、职责链模式
  • 一步操作可能分位多个职责角色来完成
  • 把这些角色都分开,然后用一个链接起来
  • 将发起者和各个处理者进行隔离
 class Action {
    constructor(name) {
        this.name =  name;
        this.nextAction = null;
    }
    setNextAction(action){
        this.nextAction= action;
    }
    handle(){
        console.log(`${this.name} 审批`);
        if(this.nextAction!==null){
            this.nextAction.handle();
        }
    }
 }
let a1 = new Action('组长');
let a2 = new Action('经理');
let a3 = new Action('总监');
a1.setNextAction(a2);
a2.setNextAction(a3);
a1.handle();
7、命令模式
  • 执行命令时候、发布者和只执行者分开
  • 中间加入命令对象,作为中转站
// 接收者
class Receiver{
    exec(){
        console.log('执行');
    }
}
// 命令者
class Command{
    constructor(receiver) {
        this.receiver = receiver;
    }
    cmd(){
        console.log('执行命令');
        this.receiver.exec();
    }
}
// 触发者
class Invoker{
    constructor(command) {
        this.command = command;
    }
    invoke(){
        console.log('开始');
        this.command.cmd();
    }
}
// 士兵
let soldier = new Receiver();
// 小号手
let  trumpeter = new Command(soldier);
// 将军
let general = new Invoker(trumpeter);
general.invoke();

8、备忘录模式
  • 随时记录一个对象的状态变化
  • 随时可以恢复之前某个状态(如撤销功能)
  • 编辑工具中的应用
// 备忘类
 class  Memento{
    constructor(content) {
        this.content =content;
    }
    getContent(){
        return this.content;
    }
 }
 // 备忘列表
 class CareTaker{
    constructor() {
        this.list = [];
    }
    add(menento){
        this.list.push(menento)
    }
    get(index){
        return this.list[index];
    }
 }
 // 编辑器
 class Editor{
    constructor() {
        this.content  = null;
    }
    setContent(content){
        this.content = content;
    }
    getContent(){
        return this.content;
    }
    saveContentToMemento(){
        return new Memento(this.content)
    }
    getContentFromMemento(memento){
        this.content = memento.getContent();
    }
 }

let editor = new Editor();
let carTaker = new CareTaker();
editor.setContent(111);
editor.setContent(222);
carTaker.add(editor.saveContentToMemento()); // 将当前内容备份
editor.setContent(333)
carTaker.add(editor.saveContentToMemento());
editor.setContent(444);
console.log(editor.getContent())
editor.getContentFromMemento(carTaker.get(1));
console.log(editor.getContent());
editor.getContentFromMemento(carTaker.get(0));
console.log(editor.getContent());
9、中介者模式
class A {
    constructor(   ) {
        this.number  = 0 ;
    }
    setNumber(num,m){
        this.number  = num;
        if(m){
            m.setB();
        }
    }
}
class B{
    constructor(

    ) {
        this.number = 0;
    }
    setNumber(num,m){
        this.number  = num;
        if(m){
            m.setA();
        }
    }
}
class Metiator{
    constructor(a,b) {
        this.a= a ;
        this.b = b ;
    }
    setB(){
        let number = this.a.number;
        this.b.setNumber(number*100);
    }
    setA(){
        let number = this.b.number;
        this.a.setNumber(number/100);
    }
}
let a = new A();
let b = new B();
let m = new Metiator(a,b);
a.setNumber(100,m);
console.log(a.number,b.number);
b.setNumber(100,m);
console.log(a.number,b.number);

10、访问者模式
  • 将数据操作和数据结构进行分离
11、解释器模式
  • 描述语言语法如何定义、如何解释和编译

四、资源

JS设计模式