js设计模式-命令模式

命令模式是一种组织型模式,主要用在把调用对象(用户界面、API和代理等)与实现操作的对象隔离开。也就是说 ,凡是两个对象间的互动方式需要更高的模块化程度时都可以用到这种模式。

命令模式的好处:1、提高程序的模块化程度和灵活性。(运用得当);2、实现取消和状态恢复等复杂的有用特性非常容易。

例子:菜单组合对象

  1 /**
  2  * 菜单组合对象
  3  */
  4 
  5 /*command,Composite and MenuObject interfaces*/
  6 var Command = new Interface("Compand",["execute"]);
  7 var Composite = new Interface("Composite",["add","remove","getChild","getElement"]);
  8 var MenuObject = new Interface("MenuObject",["show","hide"]);
  9 
 10 /*MenuBar class, a composite*/
 11 var MenuBar = function(){
 12     this.menus = {};
 13     this.element = document.createElement("ul");
 14     this.element.className = "menu-bar";
 15     this.element.style.display = "none";
 16 }
 17 MenuBar.prototype = {
 18     add:function(menuObject){
 19         Interface.ensureImplements(menuObject,Composite,MenuObject);
 20         this.menus[menuObject.name] = menuObject;
 21         this.element.appendChild(this.menus[menuObject.name].getElement());
 22     },
 23     remove:function(name){
 24         delete this.menus[name];
 25     },
 26     getChild:function(name){
 27         return this.menus[name];
 28     },
 29     getElement:function(){
 30         return this.element;
 31     },
 32     show:function(){
 33         this.element.style.display = "block";
 34         for(name in this.menus){
 35             this.menus[name].show();
 36         }
 37     },
 38     hide:function(){
 39         this.element.style.display = "none";
 40     }
 41 }
 42 
 43 /*Menu class a composite*/
 44 //备注:这里为了获取Menu对象的父对象,所以多传了一个parent,同时在实现的接口下,又多加了两个方法:showContainer和hideContainer
 45 var Menu = function(name,parent){
 46     this.name = name;
 47     this.items = {};
 48     this.parent = parent;
 49     this.element = document.createElement("li");
 50     this.element.className = "menu";
 51     this.element.innerHTML = this.name;
 52     this.element.style.display = "none";
 53     this.container = document.createElement("ul");
 54     this.element.appendChild(this.container);
 55     
 56     var that = this;
 57     this.element.addEventListener("click",function(e){
 58         e.preventDefault();
 59         e.stopPropagation();
 60         //这里在显示当前菜单选项的时候,把其他的选项全部隐藏掉
 61         var menus = that.parent.menus;
 62         if(menus){
 63             for(var name in menus){
 64                 menus[name].hideContainer();
 65             }
 66         }
 67         that.showContainer();
 68     },false);
 69     document.body.addEventListener("click",function(e){
 70         e.preventDefault();
 71         e.stopPropagation();
 72         that.hideContainer();
 73     },false);
 74 };
 75 
 76 Menu.prototype = {
 77     add:function(menuItemObject){
 78         Interface.ensureImplements(menuItemObject,Composite,MenuObject);
 79         this.items[menuItemObject.name] = menuItemObject;
 80         this.container.appendChild(this.items[menuItemObject.name].getElement());
 81     },
 82     remove:function(name){
 83         delete this.items[name];
 84     },
 85     getChild:function(name){
 86         return this.items[name];
 87     },
 88     getElement:function(){
 89         return this.element;
 90     },
 91     show:function(){
 92         this.element.style.display = "block";
 93         for(name in this.items){
 94             this.items[name].show();
 95         }
 96     },
 97     hideContainer:function(){
 98         this.container.style.display = "none";
 99     },
100     showContainer:function(){
101         this.container.style.display = "block";
102     },
103     hide:function(){
104         this.element.style.display = "none";
105     }
106 }
107 
108 /*MenuItem class, a leaf*/
109 var MenuItem = function(name,command){
110     Interface.ensureImplements(command,Command);
111     this.name = name;
112     this.element = document.createElement("li");
113     this.element.className = "menu-item";
114     this.element.style.display = "none";
115     this.anchor = document.createElement("a");
116     this.anchor.href = "#";
117     this.anchor.innerHTML = this.name;
118     this.element.appendChild(this.anchor);
119     
120     this.anchor.addEventListener("click",function(e){
121         e.preventDefault();
122         command.execute();
123     });
124 };
125 
126 MenuItem.prototype = {
127     add:function(){},
128     remove:function(){},
129     getChild:function(){},
130     getElement:function(){return this.element;},
131     show:function(){
132         this.element.style.display = "block";
133     },
134     hide:function(){
135         this.element.style.display = "none";
136     }
137 }

界面:

  1 <!DOCTYPE html>
  2 <html>
  3     <head>
  4         <meta charset="UTF-8">
  5         <title>菜单对象</title>
  6         <style type="text/css">
  7             #container{margin:0 auto;padding:0; border:1px solid #ccc; width:500px; height:50px; font-family: "微软雅黑"; font-size: 14px; text-align: center;}
  8             .menu-bar{list-style: none;padding:0;width:100%;height:50px; margin-left:50px;}
  9             .menu-bar .menu{float:left; width:80px; text-align: center; cursor: pointer;height:30px; line-height:30px;}
 10             .menu-bar .menu:hover{background:#0000DD; color:#fff;}
 11             .menu-bar .menu ul{list-style:none;width:80px; margin:0;padding:0; background:#ddd; display: none; margin-top:5px; border: 1px solid black;}
 12             /*.menu-bar .menu:nth-of-type(1) ul{display: block;}*/
 13             .menu-bar .menu .menu-item{width:70px;height:30px; line-height: 30px; border-bottom: 1px dashed #ccc;}
 14             .menu-bar .menu .menu-item a{text-decoration: none;}
 15             
 16             #result{
 17                 margin:150px auto; height:50px; line-height: 50px; border: 2px solid red; width:300px;  text-align: center; font-family: "微软雅黑"; font-size: 16px;
 18             }
 19         </style>
 20     </head>
 21     <body>
 22         <div id="container">
 23             
 24         </div>
 25         
 26         <div id="result"></div>
 27     </body>
 28 </html>
 29 <script type="text/javascript" src="Interface.js"></script>
 30 <script type="text/javascript" src="Menu.js"></script>
 31 <script type="text/javascript">
 32     var oResult = document.getElementById("result");
 33     //定义每个菜单的action
 34     function FileActions(){}
 35     FileActions.prototype = {
 36         open:function(){
 37             oResult.innerHTML = "open command is executed";
 38         },
 39         close:function(){
 40             oResult.innerHTML = "close command is executed";
 41         },
 42         save:function(){
 43             oResult.innerHTML = "save command is executed";
 44         },
 45         saveAs:function(){
 46             oResult.innerHTML = "saveAs command is executed";
 47         }
 48     }
 49     
 50     function EditActions(){}
 51     EditActions.prototype = {
 52         cut:function(){
 53             oResult.innerHTML = "cut command is executed";
 54         },
 55         copy:function(){
 56             oResult.innerHTML = "copy command is executed";
 57         },
 58         paste:function(){
 59             oResult.innerHTML = "paste command is executed";
 60         },
 61         delete:function(){
 62             oResult.innerHTML = "delete command is executed";
 63         }
 64     }
 65     
 66     function InsertActions(){}
 67     InsertActions.prototype.insert = function(){
 68         oResult.innerHTML = "insert command is executed";
 69     }
 70     
 71     function HelpActions(){}
 72     HelpActions.prototype.help = function(){
 73         oResult.innerHTML = "help command is executed";
 74     }
 75     
 76     
 77 /*MenuCommand class. a command object*/
 78 var MenuCommand = function(action){
 79     this.action = action;
 80 }
 81 MenuCommand.prototype.execute = function(){
 82     this.action();
 83 }
 84 
 85 var fileActions = new FileActions();
 86 var editActions = new EditActions();
 87 var insertActions = new InsertActions();
 88 var helpActions = new HelpActions();
 89 
 90 var appMenuBar = new MenuBar();
 91 
 92 /*fileMenu*/
 93 var fileMenu = new Menu("File",appMenuBar);
 94 
 95 fileMenu.add(new MenuItem("Open",new MenuCommand(fileActions.open)));
 96 fileMenu.add(new MenuItem("Close",new MenuCommand(fileActions.close)));
 97 fileMenu.add(new MenuItem("Save",new MenuCommand(fileActions.save)));
 98 fileMenu.add(new MenuItem("Save As",new MenuCommand(fileActions.saveAs)));
 99 
100 appMenuBar.add(fileMenu);
101 
102 /*editMenu*/
103 var editMenu = new Menu("Edit",appMenuBar);
104 
105 editMenu.add(new MenuItem("Cut",new MenuCommand(editActions.cut)));
106 editMenu.add(new MenuItem("Copy",new MenuCommand(editActions.copy)));
107 editMenu.add(new MenuItem("Paste",new MenuCommand(editActions.paste)));
108 editMenu.add(new MenuItem("Delete",new MenuCommand(editActions.delete)));
109 
110 appMenuBar.add(editMenu);
111 
112 /*the insert menu*/
113 
114 var insertMenu = new Menu("Insert",appMenuBar);
115 insertMenu.add(new MenuItem("The Block",new MenuCommand(insertActions.insert)));
116 appMenuBar.add(insertMenu);
117 
118 /*The help menu*/
119 var helpMenu = new Menu("Help",appMenuBar);
120 helpMenu.add(new MenuItem("TheHelp",new MenuCommand(helpActions.help)));
121 
122 appMenuBar.add(helpMenu);
123 
124 /*Build the menu bar*/
125 document.getElementById("container").appendChild(appMenuBar.getElement());
126 appMenuBar.show();
127         
128 </script>
原文地址:https://www.cnblogs.com/tengri/p/5352964.html