• JavaScript-其他设计模式


    其他设计模式

    JavaScript 中不常用
    对应不到经典场景

    原型模式-行为型

    • clone 自己,生成一个新对象
    • java 默认有 clone 接口,不用自己实现
    //'object.creat'用到了原型模式的思想(虽然不是java中的clone)
    //基于一个原型创建一个对象
    var prototype = {
      gatName: function() {
        return this.first + " " + this.last;
      },
      say: function() {
        console.log("hello");
      }
    };
    
    // 基于原型创建x
    var x = Object.create(prototype);
    x.first = "A";
    x.last = "B";
    console.log(x.gatName());
    x.say();
    
    //基于原型创建y
    var y = Object.create(prototype);
    y.first = "A";
    y.last = "B";
    console.log(y.gatName());
    y.say();
    
    • 对比 js 中的原型 prototype
      • prototype 可以理解为 es6 class 的一种底层原理
      • 而 class 是实现面向对象的基础,并不是服务于某个模式
      • 若干年后 es6 普及,大家可能会忽略掉 prototype
      • 但是 Object.create 却会长久存在

    桥接模式-结构型

    • 用于把抽象化与现实化解耦
    • 使得二者可以独立变化
    • js 中未找到经典应用

    class ColorShap {
      yellowCircle() {
        console.log("yellow circle");
      }
      redCircle() {
        console.log("red circle");
      }
      yellowTriangle() {
        console.log("yellow triangle");
      }
      redTriangle() {
        console.log("red triangle");
      }
    }
    
    // 测试
    let cs = new ColorShap();
    cs.yellowCircle();
    cs.redCircle();
    cs.yellowTriangle();
    cs.redTriangle;
    

    上面代码改进后

    class Color {
      constructor(name) {
        this.name = name;
      }
    }
    class Shap {
      constructor(name, color) {
        this.name = name;
        this.color = color;
      }
      draw() {
        console.log(`${this.color.name} ${this.name}`);
      }
    }
    
    // 测试代码
    
    let red = new Color("red");
    let yellow = new Color("yellow");
    let circle = new Shap("circle", red);
    circle.draw();
    let triabgle = new Shap("triangle", yellow);
    triabgle.draw();
    
    • 设计原则验证
      • 抽象与实现分离,解耦
      • 符合开放封闭原则

    组合模式-结构型

    • 生成树形结构
    • 让整体和部分具有一致的操作方式

    • js 经典应用中,未找到这吗复杂的数据结构
    • 虚拟 DOM 中的 vnode 是这种形式,但数据结构类型简单
    • 用 js 实现一个菜单,不算经典应用,与业务相关
    <!DOCTYPE html>
    <html lang="en">
      <head>
        <meta charset="UTF-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <meta http-equiv="X-UA-Compatible" content="ie=edge" />
        <title>Document</title>
      </head>
      <body>
        <div id="div1" class="container">
          <p>123</p>
          <p>456</p>
        </div>
      </body>
    </html>
    
    <script>
      var 组合模式 = {
        tag: "div",
        attr: {
          id: "div1",
          className: "container"
        },
        children: [
          {
            tag: "p",
            attr: {},
            children: ["123"]
          },
          {
            tag: "p",
            attr: {},
            children: ["456"]
          }
        ]
      };
    </script>
    
    • 整体和单个节点的操作是一致的
    • 整体和单个节点的数据结构也一致
    • 设计原则验证
      • 将整体和单个节点的操作抽象出来
      • 符合开放封闭原则

    享元模式-结构型

    • 共享内存(主要考虑内存,而非效率)
    • 相同数据,共享内存
    • js 中未找到经典应用场景
    <!DOCTYPE html>
    <html lang="en">
      <head>
        <meta charset="UTF-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <meta http-equiv="X-UA-Compatible" content="ie=edge" />
        <title>Document</title>
      </head>
      <body>
        <!-- 无限下拉列表,将事件代理到高层节点上 -->
        <!-- 如果都绑定到`<a>`标签,对内存开销太大 -->
        <div id="div1">
          <a href="#">a1</a>
          <a href="#">a2</a>
          <a href="#">a3</a>
          <a href="#">a4</a>
          <!-- 无限下拉列表 -->
        </div>
    
        <script>
          var div1 = document.getElementById("div1");
          div1.addEventListener("clink", function(e) {
            var target = e.target;
            if (e.nodeName === "A") {
              alert(target.innerHrml);
            }
          });
        </script>
      </body>
    </html>
    
    • 设计原则验证
      • 将相同的部分抽象出来
      • 符合开封闭原则

    策略模式-行为型

    • 不同策略分开处理
    • 避免出现大量if...else或者switch..case
    • js 中未找到经典应用场景
    class User {
      constructor(type) {
        this.type = type;
      }
      buy() {
        if (this.type === "ordinary") {
          console.log("普通用户购买");
        } else if (this.type === "member") {
          console.log("会员购买");
        } else if (this.type === "vip") {
          console.log("vip 用户购买");
        }
      }
    }
    
    // 测试代码
    var u1 = new User("ordinary");
    u1.buy();
    var u2 = new User("member");
    u2.buy();
    var u3 = new User("vip");
    u3.buy();
    

    上面代码改进后

    class OridinaryUser {
      buy() {
        console.log("普通用户购买");
      }
    }
    class MemberUser {
      buy() {
        console.log("会员用户购买");
      }
    }
    class vipUser {
      buy() {
        console.log("vip用户购买");
      }
    }
    
    // 测试代码
    var u1 = new OridinaryUser("ordinary");
    u1.buy();
    var u2 = new MemberUser("member");
    u2.buy();
    var u3 = new vipUser("vip");
    u3.buy();
    
    • 设计原则验证
      • 不同策略,分开处理,而不是混合在一起
      • 符合开放封闭原则

    模板方法模式-行为型

    class Action {
      handle() {
        handle1();
        handle2();
        handle3();
      }
      handle1() {
        console.log("1");
      }
      handle2() {
        console.log("2");
      }
      handle3() {
        console.log("3");
      }
    }
    

    职责连接模式-行为型

    • 一步操作可能分为多个职责角色来完成
    • 把这些角色都分开,然后用一个链串起来
    • 将发起者和各个处理者隔离
    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();
    
    • js 中的链式操作

      • 职责链模式和业务结合较多,js 中能联想到链式操作
      • jQuery 的链式操作,promise.then 的链式操作
    • 设计原则验证

      • 发起者与各个处理者隔离
      • 符合开放封闭原则

    命令模式-行为型

    • 执行命令时,发布者和执行者分开
    • 中间加入命令对象,作为中转站
    class Receive {
      exec() {
        console.log("执行");
      }
    }
    class Command {
      constructor(recever) {
        this.receive = recever;
      }
      cmd() {
        console.log("触发命令");
        this.receive.exec();
      }
    }
    class Invoker {
      constructor(command) {
        this.command = command;
      }
      invoke() {
        console.log("开始");
        this.command.cmd();
      }
    }
    
    //士兵
    let solider = new Receive();
    //小号手
    let trumpter = new Command(solider);
    //将军
    let general = new Invoker(trumpter);
    general.invoke();
    
    • js 中的应用

      • 网页富文本编辑器操作,浏览器封装了一个命令对象
      • document.exeCommand('bold')
      • document.exeCommand('undo')
    • 设计原则验证

      • 命令对象与执行对象分开,解耦
      • 符合开放封闭原则

    备忘录模式-行为型

    • 随时记录一个对象的状态变化
    • 随时可以恢复之前的某个状态(如撤销功能)
    • 未找到 js 中经典应用,除了一些工具(编辑器)
    // 状态备忘
    class Memento {
      constructor(content) {
        this.content = content;
      }
      getContent() {
        return this.content;
      }
    }
    
    // 备忘列表
    class CareTaker {
      constructor() {
        this.list = [];
      }
      add(memento) {
        this.list.push(memento);
      }
      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 careTaker = new CareTaker();
    editor.setContent("111");
    editor.setContent("222");
    careTaker.add(editor.saveContentToMemento()); //存储备忘录
    editor.setContent("333");
    careTaker.add(editor.saveContentToMemento()); //存储备忘录
    editor.setContent("444");
    
    console.log(editor.getContent());
    editor.getContentFromMemento(careTaker.get(1)); //撤销
    console.log(editor.getContent());
    editor.getContentFromMemento(careTaker.get(0)); //撤销
    console.log(editor.getContent());
    
    • 设计原则验证
      • 状态对象与使用者分开,解耦
      • 符合开放封闭原则

    中介者模式-行为型

    class Mediator {
      constructor(a, b) {
        this.a = a;
        this.b = b;
      }
      setA() {
        let number = this.b.number;
        this.a.setNumber(number * 100);
      }
      setB() {
        let number = this.a.number;
        this.b.setNumber(number / 100);
      }
    }
    
    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();
        }
      }
    }
    
    let a = new A();
    let b = new B();
    let m = new Mediator(a, b);
    a.setNumber(100);
    console.log(a.number, b.number); //100 1
    b.setNumber(100);
    console.log(a.number, b.number); //10000 100
    
    • 设计原则验证
      • 将各个关联对象通过中介者隔离
      • 符合开放封闭原则

    访问者模式-行为型

    • 将数据操作和数据结构进行分离
    • 使用场景不多

    解释器模式-行为型

    • 描述语言语法如何定义,如何解释和编译
    • 用于专业场景
  • 相关阅读:
    java1.8--OptionalInt,OptionalDouble,OptionalLong类
    java1.8--Optional类
    java1.8--Null Object模式
    JDK自带的缓存--包装类的缓存
    函数式编程--lambda表达式对比匿名内部类
    java1.8--改进的接口
    Mybatis Generator(定制化)代码生成器
    Mybatis
    git fork
    git原理图解
  • 原文地址:https://www.cnblogs.com/ygjzs/p/12241208.html
Copyright © 2020-2023  润新知