JavaScript-其餘設計模式

其餘設計模式

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;

上面代碼改進後html

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>
  • 總體和單個節點的操做是一致的
  • 總體和單個節點的數據結構也一致java

  • 設計原則驗證
    • 將總體和單個節點的操做抽象出來
    • 符合開放封閉原則

享元模式-結構型

  • 共享內存(主要考慮內存,而非效率)
  • 相同數據,共享內存
  • 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();

上面代碼改進後node

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 中的鏈式操做es6

    • 職責鏈模式和業務結合較多,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
  • 設計原則驗證
    • 將各個關聯對象經過中介者隔離
    • 符合開放封閉原則

訪問者模式-行爲型

  • 將數據操做和數據結構進行分離
  • 使用場景很少

解釋器模式-行爲型

  • 描述語言語法如何定義,如何解釋和編譯
  • 用於專業場景
相關文章
相關標籤/搜索