《JavaScript 設(shè)計(jì)模式》脫水版

面向?qū)ο?/h2>

鏈?zhǔn)秸{(diào)用

  1. 在原型上添加方法

    //類式定義
    //**區(qū)別**
    Function.prototype.addMethods = function (name, fn) {
        this.prototype[name]=fn;
        return this;
    }
    //添加方法
    var Methods = function(){};
    Methods.addMethods('checkName', function () {})
     .addMethods('checkEmail', function () {});
    //使用
    //**區(qū)別**
    var md = new Methods();
    md.checkName();
    
  2. 在對(duì)象本身添加方法

    //函數(shù)式定義
    Function.prototype.addMethods = function (name, fn) {
        //**區(qū)別**
        this[name]=fn;
        return this;
    }
    //添加方法
    var methods = function(){};
    Methods.addMethods('checkName', function () {})
     .addMethods('checkEmail', function () {});
    //使用
    //**區(qū)別**
    methods.checkName();
    

區(qū)別:在原型上定義,多個(gè)實(shí)例共享一個(gè)方法;在對(duì)象上定義,每個(gè)實(shí)例復(fù)制一份方法,易造成資源浪費(fèi),產(chǎn)生多個(gè)副本。調(diào)用方式也不一樣

封裝

  1. 靜態(tài)方法/私有方法/公有方法

    var Book = function (id, name, price) {
      //私有變量
      var num = 1;
      //私有方法
      function checkId(){};
      //公有變量和方法
      this.id = id;
      this.getName = function (){};
      this.copy = function (){};
    }
    //靜態(tài)方法,通過類訪問 `Book.belonged` `Book.resetTime()`
    //只能訪問靜態(tài)屬性,不能訪問私有變量和對(duì)象變量
    Book.belonged = 'Black Shop';
    Book.resetTime = function (){};
    //原型方法,通過實(shí)例化訪問
    //var b = new Book(1, 'You don't know JS', '$100');
    //b.isChineseBook; b.display()
    Book.prototype.isChineseBook = true;
    Book.prototype.display = function (){};
    
  2. 閉包

    有權(quán)訪問另一個(gè)作用域的變量的函數(shù),函數(shù)內(nèi)返回函數(shù)。

    var Book = (function () {
     var num = 0;
         return function (id, name, price) {
          num++;
         }
    })();
    

繼承

  1. 類式繼承

    缺點(diǎn):不能向父類傳遞參數(shù),并且父類屬性共用,改一發(fā)而動(dòng)所有實(shí)例

    var SuperClass = function () {}
    var SubClass = function () {}
    SubClass.prototype = new SuperClass();
    
  2. 構(gòu)造函數(shù)繼承

    缺點(diǎn):父類的原型方法不能被子類繼承,如果在此方法下要被繼承,就要放在構(gòu)造函數(shù)里,但每次創(chuàng)建實(shí)例都會(huì)拷貝一份,違背代碼復(fù)用原則。

    var SuperClass = function (id) {
      this.id = id;
    }
    var SubClass = function (id){
      SuperClass.call(this, id);
    }
    
  3. 組合繼承(方法和屬性分別繼承)

    var SuperClass = function (id) {
      this.id = id;
    }
    SuperClass.prototype.getId = function () {
      return this.id;
    }
    var SubClass = function (id){
      SuperClass.call(this, id);
    }
    SubClass.prototype = new SuperClass();
    
  4. 寄生式繼承

...

多態(tài)

一個(gè)函數(shù)多種調(diào)用方法,自適應(yīng)參數(shù)

創(chuàng)建型設(shè)計(jì)模式

工廠系列方法 [簡(jiǎn)單工廠/工廠方法/抽象工廠]

區(qū)別:對(duì)于分類的復(fù)雜度不同。簡(jiǎn)單工廠把各分類拆分到各類中去;工廠方法則將各分類集成到工廠方法本身里;抽象工廠可用于進(jìn)一步分類,在工廠中創(chuàng)建產(chǎn)品類簇,再使產(chǎn)品子類去繼承產(chǎn)品類簇。

// 抽象工廠方法例子

建造者模式

相比工廠模式,關(guān)注創(chuàng)建過程。如:人要關(guān)注穿的衣服,性別和愛好等,分別處理。

var Named = function (name) {
  this.wholeName = name;
  var that = this;
  (function (name) {
    const [firstName, lastName] = name.split(' ');
    if (lastName) {
      that.firstName = firstName;
      that.lastName = lastName;
    }
  })(name)
}

var Person = function (name, skill) {
  //存儲(chǔ)基類信息
  var _person = new Human();
  //關(guān)注過程處理
  _person.name = new Named(name);
  _person.skill = new Skills(skill);
  return _person;
}

原型模式

可復(fù)用,可共享耗時(shí)大的從基類中提取出來,放到原型中,通過組合/寄生繼承復(fù)用,對(duì)需要重寫的進(jìn)行重寫。

//例子

單例模式

用于管理命名空間和私有變量的私密性

var A = {
  Tool: {
    tool_1: function (){},
  },
  Util: {
    util_1: function (){},
    util_2: function (){},
  }
}
A.Tool.tool_1();
A.Util.util_2();

結(jié)構(gòu)型設(shè)計(jì)模式

外觀模式

用途:兼容底層接口

//瀏覽器兼容設(shè)計(jì)案例
function addEvent(dom, type, fn) {
    // 對(duì)于支持DOM2級(jí)事件處理程序的瀏覽器
    if(dom.addEventListener) {
        dom.addEventListener(type, fn, false);
    // 對(duì)于不支持addEventListener但支持attachEvent的瀏覽器
    } else if(dom.attachEvent) {
        dom.attachEvent('on' + type, fn);
    } else {
        dom['on' + type] = fn;
    }
}

適配器

用途:框架之間、方法參數(shù)之間、數(shù)據(jù)適配、服務(wù)器端 數(shù)據(jù)適配

框架之間:在 A 框架基礎(chǔ)上引入 B 框架,則把 B 框架的方法適配到 A 上;

方法參數(shù):例子為眾插件

//ES6 參數(shù)賦值寫法
function objAdaptor({name = '', title = '設(shè)計(jì)模式', author = 'Xiao Ming'}) {}

數(shù)據(jù)適配: 例如數(shù)組轉(zhuǎn)對(duì)象

function arrAdaptor(arr) {
  // ES6 賦值解構(gòu)寫法
  const [name, type, title, data] = arr;
  const obj = {name, type, title, data};
  return obj;
}

服務(wù)器端數(shù)據(jù)適配:盡早 對(duì)接口返回格式化成前端組件需要的格式

代理模式

用途:跨域,站長(zhǎng)統(tǒng)計(jì),jsonP。解決耦合度和資源開銷的問題,統(tǒng)一處理非同域網(wǎng)絡(luò)訪問。在兩個(gè)不能互通的對(duì)象之間起到 中介 作用。

//動(dòng)態(tài)加載 script
window.onload = function () {
  var url = 'XXX';
  var scp = document.createElement('script');
  scp.src = url;
  document.body.appendChild(scp);
}
//圖片預(yù)覽例子

裝飾者模式

包裝原有實(shí)現(xiàn),與適配器的 區(qū)別 是不需要了解原有實(shí)現(xiàn),只需要原封不動(dòng)的調(diào)用。即 封裝拓展

// 裝飾者
var decorator = function(input, fn) {
    // 獲取事件源
    var input = document.getElementById(input);
    // 若事件源已經(jīng)綁定事件
    if(typeof input.onclick === 'function') {
        // 緩存事件源原有回調(diào)函數(shù)
        var oldClickFn = input.onclick;
        // 為事件源定義新的事件
        input.onclick = function() {
            // 事件源原有回調(diào)函數(shù)
            oldClickFn();
            // 執(zhí)行事件源新增回調(diào)函數(shù)
            fn();
        }
    } else {
        input.onclick = fn;
    }
}

橋接模式

提取變化的單元,如果是橋接方法,則把變化主體通過參數(shù)傳遞到單元內(nèi);如果是把變化的單元集合到橋接類中,則把變化主體直接設(shè)置為 this。抽象實(shí)現(xiàn)層(元素綁定事件)和抽象層(修飾頁(yè)面邏輯 UI)。

//橋接方法
var changeColor = function (dom, color) {
  dom.style.color = color;
}

XXX.onmouseover = function () {
  changeColor(this.getElementsByTagName('strong')[0], 'red');
}

//橋接類
class Person {
  constructor(x,y,f) {
    // Speed 和 Speak 為多維變量
    this.speed = new Speed(x, y);
    this.font = new Speak(f);
  }
  
  move() {
    this.speed.run();
    this.font.say();
  }
}

組合模式

拆分各模塊,通過 容器+成員類 的形式進(jìn)行組合。組合要有容器類容器類和成員類均繼承同一基類,但成員類不能擁有子成員

//表單組合 缺點(diǎn):代碼好多呀 w(?Д?)w
//所有表單 容器和成員類 均繼承基類
class Base {
  constructor() {
    this.element = null;
    this.children = [];
  }
  add() {throw Error('Should rewrite this function.');}
  init() {throw Error('Should rewrite this function.');}
  getElement() {throw Error('Should rewrite this function.');}
}
/*容器類*/
class FormItem extends Base{
  constructor(id, parent) {
    super();
    this.id = id;
    this.parent =parent;
    this.init();
  }
  init() {
    this.element =document.createElement('form');
    this.element.id = this.id;
    this.element.className = 'form-item';
  }
  add(child){
    this.children.push(child);
    this.element.appendChild(child.getElement());
    return this;
  }
  getElement() { return this.element; }
  show() { this.parent.appendChild(this.element); }
}
class Group extends Base{
  constructor() {
    super();
    this.init();
  }
  init() {
    this.element = document.createElement('ul');
    this.element.className = "group-item";
  }
  add(child){
    this.children.push(child);
    var liItem =document.createElement('li');
    var childItem = liItem.appendChild(child.getElement());
    this.element.appendChild(childItem);
    return this;
  }
  getElement() { return this.element; }
}
class FieldsetItem extends Base{
  constructor(id, name) {
    super();
    this.id = id;
    this.name = name;
    this.init();
  }
  init() {
    var fieldsetDom = document.createElement('fieldset');
    fieldsetDom.id = this.id;
    fieldsetDom.className = 'fieldset-item';
    var legendDom =document.createElement('legend');
    legendDom.innerHTML = this.name;
    fieldsetDom.appendChild(legendDom);
    this.element = fieldsetDom;
  }
  add(child){
    this.children.push(child);
    this.element.appendChild(child.getElement());
    return this;
  }
  getElement() { return this.element; }
}
/*成員類*/
class LabelItem extends Base {
  constructor(id, name) {
    super();
    this.id = id;
    this.name = name;
    this.init();
  }
  init() {
    this.element = document.createElement('label');
    // 不能使用 for 關(guān)鍵字
    //this.element.for = this.id;
    //this.element.setAttribute("for",this.id);
    this.element.htmlFor = this.id;
    this.element.innerHTML = this.name;
  }
  getElement() { return this.element; }
}
class InputItem extends Base {
  constructor(id) {
    super();
    this.id = id;
    this.init();
  }
  init() {
    this.element = document.createElement('input');
    this.element.name = this.id;
    this.element.id = this.id;
    this.element.type = 'text';

  }
  getElement() { return this.element; }
}
class SpanItem extends Base{
  constructor(content) {
    super();
    this.content = content;
    this.init();
  }
  init() {
    this.element = document.createElement('span');
    this.element.innerHTML = this.content;
  }
  getElement() { return this.element; }
}

var form = new FormItem('FormItem', document.body);
form.add(
  new FieldsetItem('account', '賬號(hào)').add(
      new Group().add(
        new LabelItem('user_name', '用戶名')
      ).add(
        new InputItem('user_name')
      ).add(
        new SpanItem('4-6位數(shù)字或字母')
      )
    ).add(
      new Group().add(
        new LabelItem('user_password','密  碼')
      ).add(
        new InputItem('user_password')
      ).add(
        new SpanItem('6-12位數(shù)字或字母')
      )
    )
  ).add(
  new FieldsetItem('information', '信息').add(
      new Group().add(
        new LabelItem('nickname', ' 昵稱')
      ).add(
        new InputItem('nickname')
      )
    ).add(
      new Group().add(
        new LabelItem('status','狀態(tài)')
      ).add(
        new InputItem('status')
      )
    )
  )
  .show();

享元模式(共享模式)

共享數(shù)據(jù)或行為。把數(shù)據(jù)分為內(nèi)部數(shù)據(jù)、內(nèi)部方法和外部數(shù)據(jù)、外部方法。共享開銷大的元素,例如 dom 元素等,數(shù)據(jù)是獨(dú)立于 dom 的。相同的行為也可以提取出來作為公共元素,通過繼承等方式,減少冗余代碼。再例如彈窗。

行為型設(shè)計(jì)模式

模板方法模式

先實(shí)現(xiàn)基礎(chǔ)模板,再在模板上添加別的功能,類似 裝飾者模式,但不同是裝飾者是作為第三方存在,模板方法直接產(chǎn)出一個(gè)對(duì)象或行為,在實(shí)例上做改動(dòng),并且裝飾者不會(huì)修改原有對(duì)象或行為,模板方法會(huì)。案例就是彈層統(tǒng)一。父類中定義一組操作算法骨架,而將一些實(shí)現(xiàn)步驟延遲到子類,使得子類可以不改變父類算法結(jié)構(gòu)的同時(shí)可重新定義算法中某些實(shí)現(xiàn)步驟。

// 彈層統(tǒng)一,繼承后修改基類方法和元素, ES6

觀察者模式

發(fā)布 - 訂閱模式,和 dom 事件的異同。通過中轉(zhuǎn)站傳遞消息。

//發(fā)布-訂閱庫(kù)
var Observer = (function() {
    // 防止消息隊(duì)列暴露而被篡改,故將消息容器作為靜態(tài)私有變量保存
    var __messages = {};
    return {
        // 注冊(cè)信息接口
        regist: function() {},
        // 發(fā)布信息接口
        fire: function() {},
        // 移除信息接口
        remove: function() {}
    }
})();

狀態(tài)模式

對(duì)條件狀態(tài)判斷的每一種情況獨(dú)立管理,解決條件分支耦合問題。案例:超級(jí)瑪麗。和 橋接模式 類似,拆分多維變量,對(duì)每一種變量進(jìn)行獨(dú)立管理。

//超級(jí)瑪麗案例
class MarryState {
  constructor() {
    this._currentState = [];
    this.state = {
      jump: function (){},
      move: function (){},,
      shoot: function (){},
      squat: function (){},
    }
  }
  
  //??ES6 私有變量
  _changeState(...args) {
    this._currentState = [];
    args.forEach(action => {
      this._currentState.push(action);
    });
    return this;
  }
  
  goes() {
    this._currentState.forEach(actionName => {
      const action = this.state[actionName];
      if (action) {action();}
    });
    return this;
  }
  
  change() { return this._changeState;}
}
//調(diào)用
var marry = new MarryState();
marry.change('jump', 'shoot').goes().goes().change('shoot').goes().goes();

//盒子移動(dòng)
class BoxState {
  constructor(dom) {
    this.dom = dom;
    //this._currentState = [];
    this.step = 50;
    this.left = 0;
    this.top = 0;
    this.state = {
      37: this.moveLeft.bind(this),
      38: this.moveUp.bind(this),
      39: this.moveRight.bind(this),
      40: this.moveDown.bind(this),
    }
  }

  moveLeft() {
    this.left -= this.step;
    this.dom.style.left = this.left+'px';
  }

  moveRight() {
    this.left += this.step;
    this.dom.style.left = this.left+'px';
  }

  moveUp() {
    this.top -= this.step;
    this.dom.style.top = this.top+'px';
  }

  moveDown() {
    this.top += this.step;
    this.dom.style.top = this.top+'px';
  }

  goes(keyCode) {
    let action = this.state[keyCode];
    if (action) { action(); }
  }
}

let boxDom = document.getElementById('box');
let bx = new BoxState(boxDom);

window.addEventListener('keydown', function (e) {
  //改變狀態(tài)
  let keyCode = e.which;
  bx.goes(keyCode);
});

策略模式

類似 狀態(tài)模式,不同的是,狀態(tài)模式 核心是對(duì)狀態(tài)的控制來決定行為,策略模式 關(guān)注算法封裝,通過策略名稱調(diào)用來獲得結(jié)果。另:對(duì)于各算法共用的部分,可以通過 享元模式 解決資源浪費(fèi)問題。拓展:支持算法延伸。

//??表單驗(yàn)證策略統(tǒng)一

職責(zé)鏈模式

分解復(fù)雜模塊,簡(jiǎn)化需求。例如:服務(wù)端拉取數(shù)據(jù) -> 適配并解析新聞 -> 創(chuàng)建新聞模塊 -> 為新聞添加交互 -> 展示新聞頁(yè)。每個(gè)步驟都是一個(gè)模塊,互相調(diào)用,且可測(cè)。

命令模式

解耦請(qǐng)求與實(shí)現(xiàn)并封裝成獨(dú)立對(duì)象。

//例如繪圖調(diào)用方法
//但這樣簡(jiǎn)單的使用其實(shí)用命令模式?jīng)]什么意義
CanvasCommand.excute([
  {command: 'fillStyle', param: 'red'},
  {command: 'fillRect', param: [20, 20, 100, 100]},
]);
//??時(shí)鐘案例

訪問者模式

對(duì)原聲對(duì)象構(gòu)造器進(jìn)行封裝,對(duì)多變的操作類型進(jìn)行原生行為封裝。例如:對(duì)象也可以使用 push,splice 等方法,通過Array.prototype.splice.apply(arguments[0], args)

中介者模式

類似 觀察者模式,區(qū)別是 觀察者 是雙向訂閱模式,一個(gè)模塊既可以是消息發(fā)送者也可以是接收者,而 中介者 是消息統(tǒng)一由中介發(fā)布,所有訂閱者間接被管理。模塊與模塊之間的交互在中介者內(nèi)部完成,保持了模塊之間的獨(dú)立性。

//鍵盤方向鍵控制盒子移動(dòng)
//單例模式 中介者
class Mediator {
  static getInstance() {
    if (!Mediator.instance) {
      Mediator.instance = new Mediator();
    }
    return Mediator.instance;
  }
  constructor() {
    this._msg = {};
  }
  registry(type, cb) {
    this._msg[type] = this._msg[type] || [];
    if (cb) {this._msg[type].push(cb);}
  }
  send(type) {
    let funcs = this._msg[type];
    if (funcs) {
      funcs.forEach(func => {
        if (func) {func();}
      });
    }
  }
}

let md = Mediator.getInstance();
//盒子模型
class Box {
  constructor() {
    this.dom = document.getElementById('box');
    this.left = 0;
    this.top = 0;
    this.step = 50;
  }
  moveLeft() {
    this.left -= this.step;
    this.dom.style.left = this.left+'px';
  }

  moveRight() {
    this.left += this.step;
    this.dom.style.left = this.left+'px';
  }

  moveUp() {
    this.top -= this.step;
    this.dom.style.top = this.top+'px';
  }

  moveDown() {
    this.top += this.step;
    this.dom.style.top = this.top+'px';
  }
}

var b = new Box();

md.registry('moveLeft', b.moveLeft.bind(b));
md.registry('moveUp', b.moveUp.bind(b));
md.registry('moveRight', b.moveRight.bind(b));
md.registry('moveDown', b.moveDown.bind(b));

//發(fā)送層
window.addEventListener('keydown', function (e) {
  let keyCode = e.which;
  switch (keyCode) {
    case 37: md.send('moveLeft');break;
    case 38: md.send('moveUp');break;
    case 39: md.send('moveRight');break;
    case 40: md.send('moveDown');break;
  }
});

備忘錄模式

緩存網(wǎng)絡(luò)請(qǐng)求等其他耗時(shí)耗力的數(shù)據(jù)。配合 適配器模式 在早期格式化網(wǎng)絡(luò)請(qǐng)求數(shù)據(jù),便于今后的重復(fù)使用。

// Page備忘錄類
var Page = function() {
    // 信息緩存對(duì)象
    var cache = {};
    return function(page, fn) {
        // 判斷該頁(yè)數(shù)據(jù)是否在緩存中
        if(cache[page]) {
            // 顯示該頁(yè)內(nèi)容
            showPage(page, cache[page]);
            // 執(zhí)行成功回調(diào)函數(shù)
            fn && fn();
        } else {
            // 否則異步請(qǐng)求
            $.post('./data/getNewsData.php', {
                page: page
            }, function(res) {
                // 成功返回
                if(res.errNo == 0) {
                    showPage(page, res.data);
                    cache[page] = res.data;
                    fn && fn();
                } else {
                    // 處理異常
                }
            })
        }
    }
}

迭代器模式

對(duì)數(shù)據(jù)自定義迭代器

解釋器

技巧型設(shè)計(jì)模式

鏈模式

委托模式

冒泡 & 捕獲的區(qū)別:捕獲減少事件綁定,內(nèi)存消耗,子元素委托給父元素處理。通過委托者將請(qǐng)求委托給被委托者去處理實(shí)現(xiàn)。通過被委托者對(duì)接受到的請(qǐng)求進(jìn)行處理后,分發(fā)給相應(yīng)委托者處理。應(yīng)用有:事件處理,狀態(tài)模式 中的狀態(tài)對(duì)象,策略模式 中策略對(duì)象對(duì)接收到的算法處理,命令模式對(duì)接受到的命令處理。

數(shù)據(jù)訪問對(duì)象模式

節(jié)流模式

用戶在頁(yè)面的操作是沒有限制的,但是如果相應(yīng)用戶的頻繁操作,比如:scroll、resize、move 等,會(huì)造成動(dòng)作函數(shù)不停執(zhí)行,性能上會(huì)產(chǎn)生很大的問題。所以要延遲執(zhí)行,等用戶操作穩(wěn)定之后再處理??捎糜?浮層 show & hide 、可視范圍優(yōu)先加載,其他圖片延遲加載、統(tǒng)計(jì)打包

//簡(jiǎn)略版
function throttle(fn) {
  return function(...args) {
    let context = this
    clearTimeout(timer)
    timer = setTimeout(function() {
        fn.apply(context, args)
    }, 1000)
  }
}
//詳細(xì)版
var throttle = function (...args) {
    let isCLear = args[0];
    let fn = null;
    if (typeof isCLear === 'boolean') {
      fn = args[1];
      fn.__throttleId && clearTimeout(fn.__throttleId);
    } else {
      fn = isClear;
      param = args[1];
      let p = Object.assign({
        context: null,
        options = [],
        time: 300
      }, param);
      args.callee(true, fn);
      fn.__throttleId = setTimeout(function () {
        fn.apply(p.context, p.options);
      }, p.time);
    }
}
//??搜索框 change 事件節(jié)流

簡(jiǎn)單模板模式

架構(gòu)型設(shè)計(jì)模式

同步模塊

即 CMD、AMD 方法的實(shí)現(xiàn)。對(duì)其他模塊通過引用方式引入到自己的模塊中,互不干擾。

//??模塊化管理工具的實(shí)現(xiàn)

異步模塊

對(duì)未加載模塊的文件引用(前端限制)。

//async 方法
//實(shí)現(xiàn)對(duì)樣式模塊的依賴化加載

Widget 模式

即模板引擎。

MVC 模式

拆分?jǐn)?shù)據(jù)、視圖、業(yè)務(wù)邏輯三個(gè)層次,顯性區(qū)分三個(gè)層次,這樣還有一個(gè)好處是可以實(shí)現(xiàn)數(shù)據(jù)共享。

MVP 模式

MVVM 模式

參考

  1. 《JavaScript 設(shè)計(jì)模式》- 張榕銘
  2. 《JavaScript 設(shè)計(jì)模式》讀后感覺很復(fù)雜
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容

  • 面向?qū)ο缶幊?1.創(chuàng)建,使用函數(shù) var CheckObject = {checkName : function(...
    依米花1993閱讀 402評(píng)論 0 0
  • 工廠模式類似于現(xiàn)實(shí)生活中的工廠可以產(chǎn)生大量相似的商品,去做同樣的事情,實(shí)現(xiàn)同樣的效果;這時(shí)候需要使用工廠模式。簡(jiǎn)單...
    舟漁行舟閱讀 7,842評(píng)論 2 17
  • 單例模式 適用場(chǎng)景:可能會(huì)在場(chǎng)景中使用到對(duì)象,但只有一個(gè)實(shí)例,加載時(shí)并不主動(dòng)創(chuàng)建,需要時(shí)才創(chuàng)建 最常見的單例模式,...
    Obeing閱讀 2,103評(píng)論 1 10
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 134,923評(píng)論 18 139
  • 原文: https://github.com/ecomfe/spec/blob/master/javascript...
    zock閱讀 3,408評(píng)論 2 36