Js 设计模式

Js 设计模式

通过比对不同模式的使用,更好的理解。

创建类:
  单例模式
结构性:
  装饰模式
  代理模式
行为性:
  状态模式
  策略模式
  模板模式
  观察者模式

单例模式

代码:

// 单例模式
var someClass = {
  _singleton: null,
  getSingleton: function() {
    if (!this._singleton) {
      this._singleton = {
        // some code here
      }
    }
    return this._singleton
  }
}

var instance = someClass.getSingleton()

为了保证实例不被改写,可以关闭它的写入开关

Object.defineProperty(namespace, "singleton", { 
  writable: false, 
  configurable: false, 
  value: { 
  // some value
  } 
});
代理模式 vs 装饰模式

参考:http://www.cnblogs.com/webFrontDev/archive/2013/05/13/3075857.html

装饰者虚拟代理都要对其他对象进行包装,都要实现与被包装对象相同的接口,而且都要把方法调用传递给被包装对象。

区别:1. 装饰者会对被包装对象的功能进行修改或扩充,而代理只不过是控制对它的访问。除了有时可能会添加一些控制代码之外,代理并不会对传递给本体的方法调用进行修改。而装饰着就是为修改方法而生的。2. 另一个区别表现在被包装对象的创建方式上。在装饰者模式中,被包装对象的实例化过程是完全独立的。这个对象创建出来之后,你可以随意为其裹上一个或更多装饰者。而在代理模式中,被包装对象的实例化是代理的实例化过程的一部分。在某些类型的虚拟代理中,这种实例化受到严格控制,它必须在代理内部进行。此外,代理不会像装饰者那样互相包装,它们一次只使用一个。

代理模式

普通代理

var MyClass = function(){}
MyClass.prototype.add = function(){}
MyClass.prototype.remove = function(){}

// 普通代理
var targetProxy = function(){
  this.target = new MyClass()
}
targetProxy.prototype.add = function(){
  return this.target.add()
}
targetProxy.prototype.remove = function(){
  return this.target.remove()
}

虚拟代理

// 虚拟代理(virtual proxy) 虚拟代理用于控制对那种创建开销很大的本体的访问。其本体实例化是在使用时才进行
var targetVirtualProxy = function(){
  this.args = arguments
  this.target = null
}
targetVirtualProxy.prototype._init = function(){
  if(!this.target) this.target = new MyClass(this.args)
}
targetVirtualProxy.prototype.add = function(){
  this._init()
  return this.target.add()
}
targetVirtualProxy.prototype.remove = function(){
  this._init()
  return this.target.remove()
}

远程代理(远程代理是一种结构型模式,不同场景会对应不同的模式)

// 远程代理
var SimpleHandler = function(){}
SimpleHandler.prototype = {
  request: function(method, url, callback, postVars){
    var xhr = this.createXhrObject()
    xhr.onreadystatechange = function() {
      if(xhr.readyState !== 4) return
      ((xhr.status >= 200 && xhr.status < 300) || xhr.status === 304) ?
      callback.success(xhr.responseText) : callback.failure(xhr.status)
    }
    xhr.open(method, url, true)
    postVars = method === 'POST' ? postVars : null
    xhr.send(postVars)
  },
  createXhrObject: function(){
    //return new XMLHttpRequest()
  }
}

var StatsProxy = (function(){
  var xhrHandler = new SimpleHandler()
  var urls = {
    text: '/text',
    json: '/json'
  }

  function fetch(url, callback){
    var callback = {
      success: function(responseText){
        console.log(responseText)
        callback && callback()
      },
      failure: function(code){
        console.log(code)
      }
    }
    xhrHandler.request('GET', url, callback)
  }

  return {
    getText: function(callback){
      fetch(urls.text, callback)
    },
    getJson: function(callback){
      fetch(urls.json, callback)
    }
  }
})()
// 优化版
var WebserviceProxy = function () {
  this.xhrHandler = new SimpleHandler();
};
WebserviceProxy.prototype = {
  _xhrFailure: function (statusCode) {
      throw new Error('StatsProxy:Asynchronous request for stats failed.')
  },
  _fetchData: function (url, dataCallback, getVars) {
      var that = this
      var callback = {
          success: function (responseText) {
              var obj = eval('(' + responseText + ')')
              dataCallback(obj);
          },
          failure: that._xhrFailure
      }

      var getVarArray = []
      for (var varName in getVars) {
          getVarArray.push(varName + '=' + getVars[varName])
      }
      if (getVarArray.length > 0) {
          url = url + '?' + getVarArray.join('&')
      }

      this.xhrHandler.request('GET', url, callback)
  }
}

var StatsProxy = function(){ StatsProxy.superclass.constructor.call(this) }
function _extends(subClass, superClass){
  var F = function () {}
  F.prototype = superClass.prototype
  subClass.prototype = new F()
  subClass.prototype.constructor = subClass

  subClass.superclass = superClass.prototype
  if (superClass.prototype.constructor === Object.prototype.constructor) {
      superClass.prototype.constructor = superClass
  }
}
_extends(StatsProxy, WebserviceProxy)

StatsProxy.prototype.getText = function(callback){
  this._fetchData('/text', callback, {key: 'Jay'})
}

装饰模式

// 装饰模式
var Interface = function(){}
Interface.prototype.eat = function(){}
Interface.prototype.sleep = function(){}

var InterfaceDecorator = function(_interface){
  this._interface = _interface
}
InterfaceDecorator.prototype = {
  eat: function(){
    return this._interface.eat()
  },
  sleep: function(){
    return this._interface.sleep()
  },
  run: function(){
    return 'running.'
  }
}
// 使用
var HeadInterfaseDecorator = function(_interface){
  HeadInterfaseDecorator.superClass.constructor.call(this, _interface)
}
_extend(HeadInterfaseDecorator, InterfaceDecorator)
HeadInterfaseDecorator.prototype.eat = function(){
  return this._interface.eat() + ' and eat very much.'
}
状态模式 vs 策略模式

区别:在状态模式中,状态的变迁是由对象的内部条件决定,外界只需关心其接口,不必关心其状态对象的创建和转化;而策略模式里,采取何种策略由外部条件决定。

直接看如下代码示例,同样的功能,不同模式的实现:

状态模式

// 状态模式
!(function () {
    var LightEvent = {
        on:function(){
            console.log("关灯")
            this.state = "off"
        },
        off:function(){
            console.log("开灯")
            this.state = "on"
        }
    }
    var Light = function () {
        this.state = "off"
        this.button = null
    }
    Light.prototype.init = function(){
        var button = document.createElement("button"), self = this
        button.innerHTML = "开关"
        this.button = document.body.appendChild(button)
        this.button.onclick = function(){
            self.buttonWasPressed()
        }
    }
    Light.prototype.buttonWasPressed = function(){
        LightEvent[this.state].apply(this,arguments)
    }
    var light = new Light()
    light.init()
})()

策略模式

// 策略模式代码
!(function () {
    var delegate = function(client,delegation){
        return {
            buttonWasPressed:function(){
                return delegation.buttonWasPressed.apply(client,arguments)
            }
        }
    }
    var FSM = {
        off: {
            buttonWasPressed: function () {
                console.log("关灯")
                this.currHandler = this.onHandler
            }
        },
        on: {
            buttonWasPressed: function () {
                console.log("开灯")
                this.currHandler = this.offHandler
            }
        }
    }
    var Light = function () {
        this.offHandler = delegate(this,FSM.off)
        this.onHandler = delegate(this,FSM.on)
        this.currHandler = FSM.off
        this.button = null
    }
    Light.prototype.init = function () {
        var button = document.createElement("button"), self = this
        button.innerHTML = "开关"
        this.button = document.body.appendChild(button)
        this.button.onclick = function () {
            self.currHandler.buttonWasPressed.call(self)
        }
    }
    var light = new Light()
    light.init()
})()

示例中:仅看onclick 处理方法,
状态模式self.buttonWasPressed() 无论点击多少次,调用的都是实例(light 对象)本身的方法,每次调用内部状态自动变化;
策略模式self.currHandler.buttonWasPressed.call(self),每次调用buttonWasPressed方法时,不是直接调用实例(light 对象)的方法,而是调用指定处理者(即handler)的方法。

模板模式

优点:模板方法模式是一种实现代码复用的很好的手段。通过把子类的公共功能提炼和抽取,把公共部分放到模板中去实现。
缺点:子类、父类耦合高,要改动模板,通常子类要跟着改动。

// 模板模式
function AbstractClass() {
}

AbstractClass.prototype = {
  // 抽象的操作,必须有子类提供实现
  doPrimitiveOperation1: function(){},
  doPrimitiveOperation2: function(){},
  // 模板方法
  templateMethod: function(){
    this.doPrimitiveOperation1()
    this.doPrimitiveOperation2()
  }
}

function ConcreteClass() {
}

ConcreteClass.prototype = {
  __proto__: AbstractClass.prototype,
  doPrimitiveOperation1: function(){
    console.log('do operation1')
  },
  doPrimitiveOperation2: function(){
    console.log('do operation2')
  }
}

观察者模式

观察者模式有被称为发布订阅模式

定义:定义对象间的一种一对多的依赖关系
本质:触发联动
命名建议:目标接口的定义,建议在名称后面跟Subject;观察者接口的定义,建议在后面跟Observer;观察者接口的更新方法,建议名称为update,当然方法的参数可以根据需要定义,参数个数不限,参数类型不限。
优点:观察者模式实现了动态联动;观察者模式支持广播通信
缺点:可能会引起无谓的操作(由于是广播,一些地方不需要update 也调用了)

// 示例代码

/**
 * 目标对象,它知道观察它的观察者,并提供注册和删除观察者的接口
 */
var Subject = function(){
  this.observers = []
}
Subject.prototype = {
  attach: function(observer){
    this.observers.push(observer)
  },
  detach: function(observer){
    for(var i=0; i<this.observers.length; i++){
      if(observer == this.observers[i]){
        this.observers.splice(i, 1)
        return true
      }
    }
    return false
  },
  notifyObservers: function(){
    for(var i=0; i<this.observers.length; i++){
      this.observers[i].update(this)
    }
  }
}

/**
 * 具体的目标对象,负责把有关状态存入到对应的观察者对象
 * 自己状态发生变化时,通知各个观察者
 */
var ConcreteSubject = function(){
  ConcreteSubject.super.constructor.call(this)
  // 目标对象状态
  this.subjectState = ''
}
_extends(ConcreteSubject, Subject)
ConcreteSubject.prototype.getSubjectState = function(){
  return this.subjectState
}
ConcreteSubject.prototype.setSubjectState = function(subjectState){
  this.subjectState = subjectState
  this.notifyObservers()
}

/**
 * 观察者
 */
var Observer = function(){
}
Observer.prototype.update = function(){}

var ConcreteObserver = function(){
  this.observerState = ''
}
_extends(ConcreteObserver, Observer)
ConcreteObserver.prototype.update = function(subject){
  this.observerState = subject.getSubjectState()
}

资料地址:
javaScript 标准参考教程
js 设计模式系列

(未完,待续~)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
JavaScript 设计模式是在 JavaScript 编程中经常使用的一种代码组织和架构方法。设计模式可以帮助开发者解决常见的问题,并提供可复用的解决方案。 以下是一些常见的 JavaScript 设计模式: 1. 工厂模式(Factory Pattern):通过使用工厂方法创建对象,将对象的创建和使用分离开来,提高代码的可扩展性和可维护性。 2. 单例模式(Singleton Pattern):确保一个类只有一个实例,并提供一个全局访问点来访问该实例。 3. 观察者模式(Observer Pattern):定义了对象之间的一对多依赖关系,当一个对象的状态发生改变时,所有依赖它的对象都会被自动通知并更新。 4. 发布-订阅模式(Publish-Subscribe Pattern):也是一种观察者模式的变体,在这种模式中,发布者(Publisher)和订阅者(Subscriber)之间通过消息队列进行通信。 5. 原型模式(Prototype Pattern):通过复制现有对象来创建新对象,避免了使用类进行实例化的复杂性。 6. 适配器模式(Adapter Pattern):将一个类的接口转换成客户端所期望的另一个接口,使得原本不兼容的类可以一起工作。 7. 装饰者模式(Decorator Pattern):动态地给对象添加新的功能,而不影响其他对象。 8. 策略模式(Strategy Pattern):定义一系列算法,将每个算法封装起来,并使它们可以互换使用。 这些设计模式可以帮助开发者在编写 JavaScript 代码时更好地组织和设计代码结构,提高代码的可读性、可维护性和可扩展性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值