命令模式
命令模式是一种封装方法调用的方式,它用来对方法进行参数化处理和传送,经这样处理方法可以在任何需要的时候执行。
适用于两种情况,一是消除调用操作的对象和实现操作的对象之间的耦合,二是在创建用户界面方面,特别是需要不受限的取消操作的时候。
缺点在于增加复杂度,难以调试,所以一般不要强用。
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(); };