javascript设计模式-观察者和命令

观察者

是一种管理人与任务之间的关系的得力工具,实质就是你可以对程序中某个对象的状态进行观察,并且在其发生改变时能够得到通知。一般有两种实现方式推或拉,在这个过程中各方的职责如下:

  • 订阅者可以订阅和退订,他们还要接收,并且可以在由人投送和自己收取之间进行选择;
  • 发布者负责投关,他们可以在送出和由人取之间进行选择;
function Publisher() {
    this.subscribers = [];
}
//投送方法
Publisher.prototype.deliver = function(data) {
    this.subscribers.forEach(
        function(fn) {
            fn(data);
        }
    );
    return this;
};
//订阅方法
Function.prototype.subscribe = function(publisher) {
    var that = this;
    var alreadyExists = publisher.subscribers.some(
        function(el) {
            if ( el === that ) {
                return;
            }
        }
    );
    if ( !alreadyExists ) {
        publisher.subscribers.push(this);
    }
    return this;
};
//退订方法
Function.prototype.unsubscribe = function(publisher) {
    var that = this;
    publisher.subscribers = publisher.subscribers.filter(
        function(el) {
            if ( el !== that ) {
                return el;
            }
        }
    );
    return this;
};
var publisherObject = new Publisher;
var observerObject = function(data) {
    // process data
    console.log(data);
    // unsubscribe from this publisher
    arguments.callee.unsubscribe(publisherObject);
};
observerObject.subscribe(publisherObject);
动画
// Publisher API
var Animation = function(o) {
  this.onStart = new Publisher,//三个可监视时刻
  this.onComplete = new Publisher,
  this.onTween = new Publisher;
};
Animation.
  method('fly', function() {
    // begin animation
    this.onStart.deliver();
    for ( ... ) { // loop through frames
      // deliver frame number
      this.onTween.deliver(i); 
    }
    // end animation
    this.onComplete.deliver();
  });

// setup an account with the animation manager
var Superman = new Animation({...config properties...});

// Begin implementing subscribers
var putOnCape = function(i) { };
var takeOffCape = function(i) { };

putOnCape.subscribe(Superman.onStart);
takeOffCape.subscribe(Superman.onComplete);

// fly can be called anywhere
Superman.fly();
// for instance:
addEvent(element, 'click', function() {
  Superman.fly();
});
事件监听器
var element = document.getElementById(‘a’);
var fn1 = function(e) {
  // handle click
};
var fn2 = function(e) {
  // do other stuff with click
};

addEvent(element, ‘click’, fn1);
addEvent(element, ‘click’, fn2);

命令

是一种封装方法调用的方式,命令模式与普通函数不同。它可以用来对方法调用进行参数化处理和传送,经这样处理过的方法调用可以在任何需要的时候执行。它也可以用来消除调用操作的对象和实现操作的对象之间的耦合。

它在创建用户界面时非常有用,特别是在需要不受限制的取消操作的时候。它还可以用来替代回调函数 ,因为它能够提高在对象间传递的操作的模块化程度。

这种模式适合JSP中的ACTION的实现,在一个ACITON中封装多个命令,如果只封装一个就没有多大意思了。

/* AdCommand interface. */
var AdCommand = new Interface('AdCommand', ['execute']);

/* StopAd command class. */
var StopAd = function(adObject) { // implements AdCommand
    this.ad = adObject;
};
StopAd.prototype.execute = function() {
    this.ad.stop();
};

/* StartAd command class. */
var StartAd = function(adObject) { // implements AdCommand
    this.ad = adObject;
};
StartAd.prototype.execute = function() {
    this.ad.start();
};

/* Useage. 这种方式后,就把按钮和他需要调用的操作之间解耦了*/
var startCommand = new StartAd(action);
var stopCommand = new StopAd(action);
new UiButton('Start ', startCommand);
new UiButton('Stop ', stopCommand);
/*匿名函数的写法,省略了很多代码*/
function makeStart(adObject) {
  return function() { 
    adObject.start();
  };
}
function makeStop(adObject) {
  return function() {
    adObject.stop();
  };
}

/* Implementation code. */
var startCommand = makeStart(ads[i]);
var stopCommand = makeStop(ads[i]);
startCommand(); 
stopCommand();

多数命令模式都由以下几种角色组成,客户创建命令,调用者执行命令,接收者在命令执行时执行相应的操作。

接口格式

var Command = new Interface('Command', ['execute']);
Interface.ensureImplements(someCommand, Command);
someCommand.execute();
if(typeof someCommand != 'function') {
  throw new Error('Command isn't a function');
}

命令对象格式

/* SimpleCommand, a loosely coupled, simple command class. */
var SimpleCommand = function(receiver) { // implements Command
  this.receiver = receiver;
};
SimpleCommand.prototype.execute = function() {
  this.receiver.action();
};

/* ComplexCommand, a tightly coupled, complex command class. */
var ComplexCommand = function() { // implements Command
  this.logger = new Logger();
  this.xhrHandler = XhrManager.createXhrHandler();
  this.parameters = {};
};
ComplexCommand.prototype = {
  setParameter: function(key, value) {
    this.parameters[key] = value;
  },
  execute: function() {
    this.logger.log('Executing command');
    var postArray = [];
    for(var key in this.parameters) {
      postArray.push(key + '=' + this.parameters[key]);
    }
    var postString = postArray.join('&');
    this.xhrHandler.request(
      'POST', 
      'script.php', 
      function() {}, 
      postString
    );
  }
};

/* GreyAreaCommand, somewhere between simple and complex. */
var GreyAreaCommand = function(recevier) { // implements Command
  this.logger = new Logger();
  this.receiver = receiver;
};
GreyAreaCommand.prototype.execute = function() {
  this.logger.log('Executing command');
  this.receiver.prepareAction();
  this.receiver.action();
};

var openCommand = new MenuCommand(fileActions.open);
var openMenuItem = new MenuItem('Open', openCommand);
fileMenu.add(openMenuItem);

取消操作

这种操作其实就是把堆栈和excute相反的操作结合使用。

var MoveUp = function(cursor) { // implements ReversibleCommand
  this.cursor = cursor;
};
MoveUp.prototype = {
  execute: function() {
    cursor.move(0, -10);
  },
  undo: function() {
    cursor.move(0, 10);    
  }
};

你可能感兴趣的:(#,JavaScript设计模式,javascript,开发语言,ecmascript,设计模式,前端)