[译]你应该知道的4种JavaScript设计模式

这里介绍下面这4种设计模式

  • Module
  • Prototype
  • Observer
  • Singleton

每种模式有许多属性构成,在这我只强调以下几点:
1 Context: 在何种情况使用哪种模式?
2 问题: 我们要解决什么为题?
3 解决方案: 怎么用模式解决我们的问题?
4 实现: 怎么实现这些模式?

Module

module是JavaScript里面的类。类的一个优点是封装--使得某些状态和行为不被其他的类访问. Module设计模式允许我们有私有成员和公共成员。

Module应该是IIFE(Immediately-Invoked-Function-Expressions)这样我们就能有私有作用域-它通过闭包来保护其中的私有成员(Module返回的是一个object而不是一个function).
他应该类似于下面的样子:

(function() {
    // 在此声明私有变量或者函数

    return {
        // 在此声明公共变量或者函数
    }

})();

在return一个对象之前我们声明了些变量和函数. 外部的代码无法方位我们的私有变量或函数,因为他们不在一个作用域。下面我们看一个更具体一些的例子:

var HTMLChanger = (function() {
  var contents = 'contents'

  var changeHTML = function() {
    var element = document.getElementById('attribute-to-change');
    element.innerHTML = contents;
  }

  return {
    callChangeHTML: function() {
      changeHTML();
      console.log(contents);
    }
  };

})();

HTMLChanger.callChangeHTML();       // Outputs: 'contents'
console.log(HTMLChanger.contents);  // undefined

注意callChangeHTML绑定在返回的对象里面,能在HTMLChanger命名空间中被引用。然而在此module外,contents是不能被访问的。

Revealing Module

Revealing是Module模式的一个变种。 目的是维持封装并且通过返回的对象字面量暴露一些变量和方法。他应该类似于下面的样子:

var Exposer = (function() {
  var privateVariable = 10;

  var privateMethod = function() {
    console.log('Inside a private method!');
    privateVariable++;
  }

  var methodToExpose = function() {
    console.log('This is a method I want to expose!');
  }

  var otherMethodIWantToExpose = function() {
    privateMethod();
  }

  return {
      first: methodToExpose,
      second: otherMethodIWantToExpose
  };
})();

Exposer.first();        // Output: This is a method I want to expose!
Exposer.second();       // Output: Inside a private method!
Exposer.methodToExpose; // undefined

Prototype

为了克隆一个对象必须先要有一个用力实例化对象的构造函数。 然后通过关键字prototype来将变量和方法绑定到对象结构中。看看下面的例子:

var TeslaModelS = function() {
  this.numWheels    = 4;
  this.manufacturer = 'Tesla';
  this.make         = 'Model S';
}

TeslaModelS.prototype.go = function() {
  // Rotate wheels
}

TeslaModelS.prototype.stop = function() {
  // Apply brake pads
}

当创建了一个TeslaModelS对象,他会保持构造函数里面初始化的状态。可以通过另外一个方法在prototype上扩展功能:

var TeslaModelS = function() {
  this.numWheels    = 4;
  this.manufacturer = 'Tesla';
  this.make         = 'Model S';
}

TeslaModelS.prototype = {
  go: function() {
    // Rotate wheels
  },
  stop: function() {
    // Apply brake pads
  }
}

Revealing Prototype

var TeslaModelS = function() {
  this.numWheels    = 4;
  this.manufacturer = 'Tesla';
  this.make         = 'Model S';
}

TeslaModelS.prototype = function() {

  var go = function() {
    // Rotate wheels
  };

  var stop = function() {
    // Apply brake pads
  };

  return {
    pressBrakePedal: stop,
    pressGasPedal: go
  }

}();

Observer

我们经常会遇到这样的情况当一个应用的某部分发生了改变的时候,该应用的其他部分需要被更新。在AngularJS中如果$scope对象更新了,一个事件将会被触发通知到其他的组件。观察者模式就是用来干这个事情的。

另一个例子是model-view-controller(MVC)架构;当model更新了,view会发生变化。

var Subject = function() {
  this.observers = [];

  return {
    subscribeObserver: function(observer) {
      this.observers.push(observer);
    },
    unsubscribeObserver: function(observer) {
      var index = this.observers.indexOf(observer);
      if(index > -1) {
        this.observers.splice(index, 1);
      }
    },
    notifyObserver: function(observer) {
      var index = this.observers.indexOf(observer);
      if(index > -1) {
        this.observers[index].notify(index);
      }
    },
    notifyAllObservers: function() {
      for(var i = 0; i < this.observers.length; i++){
        this.observers[i].notify(i);
      };
    }
  };
};

var Observer = function() {
  return {
    notify: function(index) {
      console.log("Observer " + index + " is notified!");
    }
  }
}

var subject = new Subject();

var observer1 = new Observer();
var observer2 = new Observer();
var observer3 = new Observer();
var observer4 = new Observer();

subject.subscribeObserver(observer1);
subject.subscribeObserver(observer2);
subject.subscribeObserver(observer3);
subject.subscribeObserver(observer4);

subject.notifyObserver(observer2); // Observer 2 is notified!

subject.notifyAllObservers();
// Observer 1 is notified!
// Observer 2 is notified!
// Observer 3 is notified!
// Observer 4 is notified!

Singleton

var printer = (function () {

  var printerInstance;

  function create () {

    function print() {
      // underlying printer mechanics
    }

    function turnOn() {
      // warm up
      // check for paper
    }

    return {
      // public + private states and behaviors
      print: print,
      turnOn: turnOn
    };
  }

  return {
    getInstance: function() {
      if(!printerInstance) {
        printerInstance = create();
      }
      return printerInstance;
    }
  };

  function Singleton () {
    if(!printerInstance) {
      printerInstance = intialize();
    }
  };

})();

var officePrinter = printer.getInstance();
posted @ 2016-07-14 17:26  irocker  阅读(881)  评论(0编辑  收藏  举报