命令模式

命令模式是一种封装方法调用的方式,它用来对方法进行参数化处理和传送,经这样处理方法可以在任何需要的时候执行。

适用于两种情况,一是消除调用操作的对象和实现操作的对象之间的耦合,二是在创建用户界面方面,特别是需要不受限的取消操作的时候。

缺点在于增加复杂度,难以调试,所以一般不要强用。

 

1.简单命令对象一般用来消除接收者和调用者的耦合

var SimpleCommand = function(receiver) { // implements Command
  this.receiver = receiver;
};
SimpleCommand.prototype.execute = function() {
  this.receiver.action();
};
var Command = new Interface('Command', ['execute']);
var Composite = new Interface('Composite', ['add', 'remove', 'getChild', 
  'getElement']);
var MenuObject = new Interface('MenuObject', ['show']);

/* MenuBar class, a composite. */

var MenuBar = function() { // implements Composite, MenuObject
  this.menus = {};
  this.element = document.createElement('ul');
  this.element.style.display = 'none';
};
MenuBar.prototype = {
  add: function(menuObject) {
    Interface.ensureImplements(menuObject, Composite, MenuObject);
    this.menus[menuObject.name] = menuObject;
    this.element.appendChild(this.menus[menuObject.name].getElement());
  },
  remove: function(name) {
    delete this.menus[name];
  },
  getChild: function(name) {
    return this.menus[name];
  },
  getElement: function() {
    return this.element;
  },
  
  show: function() {
    this.element.style.display = 'block';
    for(name in this.menus) { // Pass the call down the composite.
      this.menus[name].show();
    }
  }
};

/* Menu class, a composite. */

var Menu = function(name) { // implements Composite, MenuObject
  this.name = name;
  this.items = {};
  this.element = document.createElement('li');
  this.element.innerHTML = this.name;
  this.element.style.display = 'none';
  this.container = document.createElement('ul');
  this.element.appendChild(this.container);
};
Menu.prototype = {
  add: function(menuItemObject) {
    Interface.ensureImplements(menuItemObject, Composite, MenuObject);
    this.items[menuItemObject.name] = menuItemObject;
    this.container.appendChild(this.items[menuItemObject.name].getElement());
  },
  remove: function(name) {
    delete this.items[name];
  },
  getChild: function(name) {
    return this.items[name];
  },
  getElement: function() {
    return this.element;
  },
  
  show: function() {
    this.element.style.display = 'block';
    for(name in this.items) { // Pass the call down the composite.
      this.items[name].show();
    }
  }
};

/* MenuItem class, a leaf. */

var MenuItem = function(name, command) { // implements Composite, MenuObject
  Interface.ensureImplements(command, Command);
  this.name = name;
  this.element = document.createElement('li');
  this.element.style.display = 'none';
  this.anchor = document.createElement('a');
  this.anchor.href = '#'; // To make it clickable.
  this.element.appendChild(this.anchor);
  this.anchor.innerHTML = this.name;

  addEvent(this.anchor, 'click', function(e) { // Invoke the command on click.
    e.preventDefault(); 
    command.execute();
  });
};
MenuItem.prototype = {
  add: function() {},
  remove: function() {},
  getChild: function() {},
  getElement: function() {
    return this.element;
  },
  
  show: function() {
    this.element.style.display = 'block';
  }
};


/* MenuCommand class, a command object. */

var MenuCommand = function(action) { // implements Command
  this.action = action;
};
MenuCommand.prototype.execute = function() {
  this.action();
};


/* Implementation code. */

/* Receiver objects, instantiated from existing classes. */
var fileActions = new FileActions();
var editActions = new EditActions();
var insertActions = new InsertActions();
var helpActions = new HelpActions();

/* Create the menu bar. */
var appMenuBar = new MenuBar();

/* The File menu. */
var fileMenu = new Menu('File');

var openCommand = new MenuCommand(fileActions.open);
var closeCommand = new MenuCommand(fileActions.close);
var saveCommand = new MenuCommand(fileActions.save);
var saveAsCommand = new MenuCommand(fileActions.saveAs);

fileMenu.add(new MenuItem('Open', openCommand));
fileMenu.add(new MenuItem('Close', closeCommand));
fileMenu.add(new MenuItem('Save', saveCommand));
fileMenu.add(new MenuItem('Save As...', saveAsCommand));

appMenuBar.add(fileMenu);

/* The Edit menu. */
var editMenu = new Menu('Edit');

var cutCommand = new MenuCommand(editActions.cut);
var copyCommand = new MenuCommand(editActions.copy);
var pasteCommand = new MenuCommand(editActions.paste);
var deleteCommand = new MenuCommand(editActions.delete);

editMenu.add(new MenuItem('Cut', cutCommand));
editMenu.add(new MenuItem('Copy', copyCommand));
editMenu.add(new MenuItem('Paste', pasteCommand));
editMenu.add(new MenuItem('Delete', deleteCommand));

appMenuBar.add(editMenu);

/* The Insert menu. */
var insertMenu = new Menu('Insert');

var textBlockCommand = new MenuCommand(insertActions.textBlock);
insertMenu.add(new MenuItem('Text Block', textBlockCommand));

appMenuBar.add(insertMenu);

/* The Help menu. */
var helpMenu = new Menu('Help');

var showHelpCommand = new MenuCommand(helpActions.showHelp);
helpMenu.add(new MenuItem('Show Help', showHelpCommand));

appMenuBar.add(helpMenu);

/* Build the menu bar. */
document.getElementsByTagName('body')[0].appendChild(appMenuBar.getElement());
appMenuBar.show();


/* Adding more menu items later on. */

var imageCommand = new MenuCommand(insertActions.image);
insertMenu.add(new MenuItem('Image', imageCommand));

2.复杂命令对象一般用来封装不可分的或事务性的复杂指令,并没有接收者

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();
};
posted @ 2013-02-25 15:50  瓦尔登湖的秋天  阅读(165)  评论(0编辑  收藏  举报