参考 JavaScript 中常见的十五种设计模式(上) JavaScript 中常见的十五种设计模式(下) 
单例模式 定义 保证一个类仅有一个实例,并提供一个访问它的全局访问点
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 function  SetManager (name ) {  this .manager  = name; } SetManager .prototype getName  = function  (  console .log (this .manager ); }; function  getSingleton (fn ) {  let  instance = null ;   return  function  (     if  (!instance) {       instance = fn.apply (this , arguments );        console .log ("arguments:  "  + JSON .stringify (arguments ));      }     return  instance;   }; } let  managerSingleton = getSingleton (function  (name ) {  let  manager = new  SetManager (name);   return  manager; }); managerSingleton ("a" ).getName (); managerSingleton ("b" ).getName (); managerSingleton ("c" ).getName (); 
策略模式 定义 定义一系列的算法,把它们一个个封装起来,并且使它们可以相互替换
分离 使用  ← 分离 → 实现 
组成 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 let  errorMsgs = {  default : "输入数据格式不正确" ,   minLength : "输入数据长度不足" ,   isNumber : "请输入数字" ,   required : "内容不为空" , }; let  rules = {  minLength : function  (value, length, errorMsg ) {     if  (value.length  < length) {       return  errorMsg || errorMsgs["minLength" ];     }   },   isNumber : function  (value, errorMsg ) {     if  (!/\d+/ .test (value)) {       return  errorMsg || errorMsgs["isNumber" ];     }   },   required : function  (value, errorMsg ) {     if  (value === "" ) {       return  errorMsg || errorMsgs["required" ];     }   }, }; function  Validator (  this .items  = []; } Validator .prototype   constructor : Validator ,      add : function  (value, rule, errorMsg ) {     let  arg = [value];     if  (rule.indexOf ("minLength" ) !== -1 ) {       let  temp = rule.split (":" );       arg.push (temp[1 ]);       rule = temp[0 ];     }     arg.push (errorMsg);     this .items .push (function  (              return  rules[rule].apply (this , arg);     });   },      start : function  (     for  (let  i = 0 ; i < this .items .length ; ++i) {       let  ret = this .items [i]();       if  (ret) {         console .log (ret);                }     }   }, }; function  testTel (val ) {  return  val; } let  validate = new  Validator ();validate.add (testTel ("ccc" ), "isNumber" , "只能为数字" );  validate.add (testTel ("" ), "required" );  validate.add (testTel ("123" ), "minLength:5" , "最少5位" );  validate.add (testTel ("12345" ), "minLength:5" , "最少5位" ); let  ret = validate.start ();console .log (ret);
代理模式 保护代理 虚拟代理 在控制对主体的访问时,加入了一些额外的操作
缓存代理 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69      throttle (fn, delay, mustRunDelay ) {          let  timer = null      let  t_start     return  function  (       let  context = this , args = arguments , t_curr = +new  Date ()              clearTimeout (timer)       if  (!t_start) {         t_start = t_curr       }              if  (t_curr - t_start >= mustRunDelay) {         fn.apply (context, args)         t_start = t_curr       }       else  {                  timer = setTimeout (function  (           fn.apply (context, args)         }, delay)       }     }   } function  add  (  let  arg = [].slice .call (arguments );   return  arg.reduce ((a, b ) =>  { a + b }); } let  proxyAdd = (function  (  let  cache = [];   return  function  (     let  arg = [].slice .call (arguments ).join (',' );          if  (cache[arg]) {       return  cache[arg];     } else  {       let  ret = add.apply (this , arguments );       return  ret;     }   }; })(); console .log (  add (1 , 2 , 3 , 4 ),   add (1 , 2 , 3 , 4 ),   proxyAdd (10 , 20 , 30 , 40 ),   proxyAdd (10 , 20 , 30 , 40 ) );  
迭代器模式 迭代器模式是指提供一种方法 顺序访问 一个聚合对象中的各个元素,而又不需要暴露该对象的内部表示
在使用迭代器模式之后,即使不关心对象的内部构造,也可以按顺序访问其中的每个元素
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 function  createIterator (items ) {  let  i = 0 ;   return  {     next : function  (       let  done = i >= items.length ;       let  value = !done ? items[i++] : undefined ;       return  {         done : done,         value : value,       };     },   }; } let  iterator = createIterator ([1 , 2 , 3 ]);console .log (iterator.next ()); console .log (iterator.next ()); console .log (iterator.next ()); console .log (iterator.next ()); console .log (iterator.next ()); function  year2000 (  let  year = new  Date ().getFullYear ();   if  (year <= 2000 ) {     console .log ("A" );   }   return  false ; } function  year2100 (  let  year = new  Date ().getFullYear ();   if  (year >= 2100 ) {     console .log ("C" );   }   return  false ; } function  year (  let  year = new  Date ().getFullYear ();   if  (year > 2000  && year < 2100 ) {     console .log ("B" );   }   return  false ; } function  iteratorYear (  for  (let  i = 0 ; i < arguments .length ; ++i) {     let  ret = arguments [i]();     if  (ret !== false ) {       return  ret;     }   } } let  manager = iteratorYear (year2000, year2100, year); 
发布-订阅模式 也称作观察者模式
eg 小 A 在公司 C 完成了笔试及面试,小 B 也在公司 C 完成了笔试。他们焦急地等待结果,每隔半天就电话询问公司 C,导致公司 C 很不耐烦。
一种解决办法是 AB 直接把联系方式留给 C,有结果的话 C 自然会通知 AB
这里的询问属于显示 调用,留给属于 订阅,通知属于 发布
优缺点 优 一为时间上的解耦,二为对象之间的解耦
缺 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 let  observer = {     subscribes : [],      subscribe : function  (type, fn ) {     if  (!this .subscribes [type]) {       this .subscribes [type] = [];     }          typeof  fn === "function"  && this .subscribes [type].push (fn);        },      publish : function  (     let  type = [].shift .call (arguments ),       fns = this .subscribes [type];     console .log ("发布  " , fns);          if  (!fns || !fns.length ) {       return ;     }          for  (let  i = 0 ; i < fns.length ; ++i) {       fns[i].apply (this , arguments );     }   },      remove : function  (type, fn ) {          if  (typeof  type === "undefined" ) {       this .subscribes  = [];       return ;     }     let  fns = this .subscribes [type];          if  (!fns || !fns.length ) {       return ;     }     if  (typeof  fn === "undefined" ) {       fns.length  = 0 ;       return ;     }          for  (let  i = 0 ; i < fns.length ; ++i) {       if  (fns[i] === fn) {         fns.splice (i, 1 );       }     }   }, }; function  jobListForA (jobs ) {  console .log ("A" , jobs); } function  jobListForB (jobs ) {  console .log ("B" , jobs); } observer.subscribe ("job" , jobListForA); observer.subscribe ("job" , jobListForB); observer.subscribe ("examinationA" , function  (score ) {   console .log (score); }); observer.subscribe ("examinationB" , function  (score ) {   console .log (score); }); observer.subscribe ("interviewA" , function  (result ) {   console .log (result); }); observer.publish ("examinationA" , 100 );  observer.publish ("examinationB" , 80 );  observer.publish ("interviewA" , "备用" );  observer.publish ("job" , ["前端" , "后端" , "测试" ]);  observer.remove ("examinationB" ); observer.remove ("job" , jobListForA); observer.publish ("examinationB" , 80 );  observer.publish ("job" , ["前端" , "后端" , "测试" ]);  
命令模式 实现 简单的命令模式实现可以直接使用 对象字面量 的形式定义一个命令
1 2 3 4 5 let  incrementCommand = {  execute : function  (        }, }; 
采用对象创建处理的方式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 function  IncrementCommand (     this .val  = 0 ;      this .stack  = [];      this .stackPosition  = -1 ; } IncrementCommand .prototype   constructor : IncrementCommand ,      execute : function  (     this ._clearRedo ();          let  command = function  (       this .val  += 2 ;     }.bind (this );          command ();     this .stack .push (command);     this .stackPosition ++;     this .getValue ();   },   canUndo : function  (     return  this .stackPosition  >= 0 ;   },   canRedo : function  (     return  this .stackPosition  < this .stack .length  - 1 ;   },      undo : function  (     if  (!this .canUndo ()) {       return ;     }     this .stackPosition --;          let  command = function  (       this .val  -= 2 ;     }.bind (this );          command ();     this .getValue ();   },      redo : function  (     if  (!this .canRedo ()) {       return ;     }          this .stack [++this .stackPosition ]();     this .getValue ();   },      _clearRedo : function  (     this .stack  = this .stack .slice (0 , this .stackPosition  + 1 );   },      getValue : function  (     console .log (this .val );   }, }; 
组合模式 使用组合模式来实现扫描文件夹中的文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 function  Folder (name ) {  this .name  = name;   this .parent  = null ;   this .files  = []; } Folder .prototype   constructor : Folder ,   add : function  (file ) {     file.parent  = this ;     this .files .push (file);     return  this ;   },   scan : function  (          for  (let  i = 0 ; i < this .files .length ; ++i) {       this .files [i].scan ();     }   },   remove : function  (file ) {     if  (typeof  file === "undefined" ) {       this .files  = [];       return ;     }     for  (let  i = 0 ; i < this .files .length ; ++i) {       if  (this .files [i] === file) {         this .files .splice (i, 1 );       }     }   }, }; function  File (name ) {  this .name  = name;   this .parent  = null ; } File .prototype   constructor : File ,   add : function  (     console .log ("文件里面不能添加文件" );   },   scan : function  (     let  name = [this .name ];     let  parent = this .parent ;     while  (parent) {       name.unshift (parent.name );       parent = parent.parent ;     }     console .log (name.join (" / " ));   }, }; 
实例化,在组合对象中插入组合或叶对象
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 let  web = new  Folder ("Web" );let  fe = new  Folder ("前端" );let  css = new  Folder ("CSS" );let  js = new  Folder ("js" );let  rd = new  Folder ("后端" );web.add (fe).add (rd); let  file1 = new  File ("HTML权威指南.pdf" );let  file2 = new  File ("CSS权威指南.pdf" );let  file3 = new  File ("JavaScript权威指南.pdf" );let  file4 = new  File ("MySQL基础.pdf" );let  file5 = new  File ("Web安全.pdf" );let  file6 = new  File ("Linux菜鸟.pdf" );css.add (file2); fe.add (file1).add (file3).add (css).add (js); rd.add (file4).add (file5); web.add (file6); rd.remove (file4); web.scan (); 
模板方法模式 模板方法模式一般的实现方式为继承
以运动作为例子,运动有比较通用的一些处理,这部分可以抽离开来,在父类中实现。具体某项运动的特殊性则有自类来重写实现。
最终子类直接调用父类的模板函数来执行
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 function  Sport (Sport .prototype   constructor : Sport ,      init : function  (     this .stretch ();     this .jog ();     this .deepBreath ();     this .start ();     let  free = this .end ();          if  (free !== false ) {       this .stretch ();     }   },      stretch : function  (     console .log ("拉伸" );   },      jog : function  (     console .log ("慢跑" );   },      deepBreath : function  (     console .log ("深呼吸" );   },      start : function  (     throw  new  Error ("子类必须重写此方法" );   },      end : function  (     console .log ("运动结束" );   }, }; function  Basketball (Basketball .prototype new  Sport ();Basketball .prototype start  = function  (  console .log ("先投上几个三分" ); }; Basketball .prototype end  = function  (  console .log ("运动结束了,有事先走一步" );   return  false ; }; function  Marathon (Marathon .prototype new  Sport ();let  basketball = new  Basketball ();let  marathon = new  Marathon ();basketball.init (); marathon.init (); 
享元模式 享元(flyweight)模式是一种用于性能优化的模式,它的目标是尽量减少共享对象的数量
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 function  Fitness (sex ) {  this .sex  = sex; } let  FitnessFactory  = {  objs : [],   create : function  (sex ) {     if  (!this .objs [sex]) {       this .objs [sex] = new  Fitness (sex);     }     return  this .objs [sex];   }, }; let  FitnessManager  = {  fitnessData : {},      add : function  (name, sex, age, height, weight ) {     let  fitness = FitnessFactory .create (sex);          this .fitnessData [name] = {       age : age,       height : height,       weight : weight,     };     return  fitness;   },      updateFitnessData : function  (name, obj ) {     let  fitnessData = this .fitnessData [name];     for  (let  item in  fitnessData) {       if  (fitnessData.hasOwnProperty (item)) {         obj[item] = fitnessData[item];       }     }   }, }; Fitness .prototype judge  = function  (name ) {     FitnessManager .updateFitnessData (name, this );   let  ret = name + ": " ;   if  (this .sex  === "male" ) {     ret += this .judgeMale ();   } else  {     ret += this .judgeFemale ();   }   console .log (ret); }; Fitness .prototype judgeMale  = function  (  let  ratio = this .height  / this .weight ;   return  this .age  > 20  ? ratio > 3.5  : ratio > 2.8 ; }; Fitness .prototype judgeFemale  = function  (  let  ratio = this .height  / this .weight ;   return  this .age  > 20  ? ratio > 4  : ratio > 3 ; }; let  a = FitnessManager .add ("A" , "male" , 18 , 160 , 80 );let  b = FitnessManager .add ("B" , "male" , 21 , 180 , 70 );let  c = FitnessManager .add ("C" , "female" , 28 , 160 , 80 );let  d = FitnessManager .add ("D" , "male" , 18 , 170 , 60 );let  e = FitnessManager .add ("E" , "female" , 18 , 160 , 40 );a.judge ("A" );  b.judge ("B" );  c.judge ("C" );  d.judge ("D" );  e.judge ("E" );  
职责链模式 定义 使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系,将这些对象连成一条链,并沿着这条链 传递该请求,直到有一个对象处理
它为止
核心 请求发送者只需要知道链中的第一个节点,弱化发送者和一组接收者之间的强联系,可以便捷地在职责链中增加或删除一个节点,同样地,指定谁是第一个节
点也很便捷
实现 展示不同类型的变量
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 function  ChainItem (fn ) {  this .fn  = fn;   this .next  = null ; } ChainItem .prototype   constructor : ChainItem ,      setNext : function  (next ) {     this .next  = next;     console .log ("next:  "  + next);     return  next;   },      start : function  (     this .fn .apply (this , arguments );   },      toNext : function  (     if  (this .next ) {       this .start .apply (this .next , arguments );     } else  {       console .log ("无匹配的执行项目" );     }   }, }; function  showNumber (num ) {  if  (typeof  num === "number" ) {     console .log ("number" , num);   } else  {          this .toNext (num);     console .log ("数字后下一步" );   } } function  showString (str ) {  if  (typeof  str === "string" ) {     console .log ("string" , str);   } else  {     this .toNext (str);   } } function  showObject (obj ) {  if  (typeof  obj === "object" ) {     console .log ("object" , obj);   } else  {     this .toNext (obj);   } } let  chainNumber = new  ChainItem (showNumber);let  chainString = new  ChainItem (showString);let  chainObject = new  ChainItem (showObject);let  next1 = chainObject.setNext (chainNumber);console .log ("next1:  "  + JSON .stringify (next1)); let  next2 = next1.setNext (chainString);console .log ("next2:  "  + JSON .stringify (next2)); chainString.start ("12" );  chainNumber.start ({});  chainObject.start ({});  chainObject.start (123 );  
这时想判断未定义的时候呢,直接加到链中即可
1 2 3 4 5 6 7 8 9 10 11 12 13 function  showUndefined (obj ) {  if  (typeof  obj === "undefined" ) {     console .log ("undefined" );   } else  {     this .toNext (obj);   } } let  chainUndefined = new  ChainItem (showUndefined);chainString.setNext (chainUndefined); chainNumber.start ();  
对象增多,结构更清晰,一定程度上可能影响性能,注意避免过长的职责链
中介者模式 定义 所有的相关 对象都通过中介者对象来通信,而不是互相引用,所以当一个对象发生改变时,只需要通知中介者对象即可
核心 使网状的多对多关系变成了相对简单的一对多关系(复杂的调度处理都交给中介者)
实现 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 let  A = {  score : 10 ,   changeTo : function  (score ) {     this .score  = score;          this .getRank ();   },      getRank : function  (     let  scores = [this .score , B.score , C.score ].sort (function  (a, b ) {       return  a < b;     });     console .log (scores.indexOf (this .score ) + 1 );   }, }; let  B = {  score : 20 ,   changeTo : function  (score ) {     this .score  = score;          rankMediator (B);   }, }; let  C = {  score : 30 ,   changeTo : function  (score ) {     this .score  = score;     rankMediator (C);   }, }; function  rankMediator (person ) {  let  scores = [A.score , B.score , C.score ].sort (function  (a, b ) {     return  a < b;   });   console .log (scores.indexOf (person.score ) + 1 ); } A.changeTo (100 );  B.changeTo (200 );  C.changeTo (50 );  
虽然中介者做到了对模块和对象的解耦,但有时对象之间的关系并非一定要解耦,强行使用中介者来整合,可能会使代码更为繁琐,需要注意
装饰者模式 1. 定义 以动态地给某个对象添加一些额外的职责,而不会影响从这个类中派生的其他对象。
2. 核心 是为对象动态加入行为,经过多重包装,可以形成一条装饰链
3. 实现 最简单的装饰者,就是重写对象的属性
1 2 3 4 5 let  A = {  score : 10 , }; A.score  = "分数:"  + A.score ; 
可以使用传统面向对象的方法来实现装饰,添加技能
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 function  Person (Person .prototype skill  = function  (  console .log ("数学" ); }; function  MusicDecorator (person ) {  this .person  = person; } MusicDecorator .prototype skill  = function  (  this .person .skill ();   console .log ("音乐" ); }; function  RunDecorator (person ) {  this .person  = person; } RunDecorator .prototype skill  = function  (  this .person .skill ();   console .log ("跑步" ); }; let  person = new  Person ();let  person1 = new  MusicDecorator (person);person1 = new  RunDecorator (person1); person.skill ();  person1.skill ();  
更简洁的写法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 function  decoratorBefore (fn, beforeFn ) {  return  function  (     let  ret = beforeFn.apply (this , arguments );          if  (ret !== false ) {       fn.apply (this , arguments );     }   }; } function  skill (  console .log ("数学" ); } function  skillMusic (  console .log ("音乐" ); } function  skillRun (  console .log ("跑步" ); } let  skillDecorator = decoratorBefore (skill, skillMusic);skillDecorator = decoratorBefore (skillDecorator, skillRun); skillDecorator (); 
状态模式 1. 定义 事物内部状态的改变往往会带来事物的行为改变。在处理的时候,将这个处理委托给当前的 状态对象 即可,该状态对象会负责渲染它自身的行为
2. 核心 区分事物内部的状态,把事物的每种状态都封装成单独的类,跟此种状态有关的行为都被封装在这个类的内部
3. 实现 以一个人的工作状态作为例子,在刚醒、精神、疲倦几个状态中切换着
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 function  Work (name ) {  this .name  = name;   this .currentState  = null ;      this .wakeUpState  = new  WakeUpState (this );      this .energeticState  = new  EnergeticState (this );      this .tiredState  = new  TiredState (this );   this .init (); } Work .prototype init  = function  (  this .currentState  = this .wakeUpState ;      document .body .onclick  = () =>  {     this .currentState .behaviour ();   }; }; Work .prototype setState  = function  (state ) {  this .currentState  = state; }; function  WakeUpState (work ) {  this .work  = work; } WakeUpState .prototype behaviour  = function  (  console .log (this .work .name , ":" , "刚醒呢,睡个懒觉先" );      setTimeout (() =>  {     this .work .setState (this .work .energeticState );   }, 2  * 1000 ); }; function  EnergeticState (work ) {  this .work  = work; } EnergeticState .prototype behaviour  = function  (  console .log (this .work .name , ":" , "超级精神的" );      setTimeout (() =>  {     this .work .setState (this .work .tiredState );   }, 1000 ); }; function  TiredState (work ) {  this .work  = work; } TiredState .prototype behaviour  = function  (  console .log (this .work .name , ":" , "怎么肥事,好困" );      setTimeout (() =>  {     this .work .setState (this .work .wakeUpState );   }, 1000 ); }; let  work = new  Work ("曹操" );
4. 优缺点 优点 状态切换逻辑分布在状态类中,易于维护
缺点 多个状态类,影响性能,可用享元模式进一步优化
将逻辑分散在状态类中,不易看出状态机变化逻辑
十四、适配器模式 定义 是解决两个软件实体间的接口不兼容的问题,对不兼容的部分进行适配
实现 比如一个简单的数据格式转换的适配器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 function  renderData (data ) {  data.forEach (function  (item ) {     console .log (item);   }); } function  arrayAdapter (data ) {  if  (typeof  data !== "object" ) {     return  [];   }   if  (Object .prototype toString .call (data) === "[object Array]" ) {     return  data;   }   let  temp = [];   for  (let  item in  data) {               if  (data.hasOwnProperty (item)) {       temp.push (data[item]);     }   }   return  temp; } let  data = {  0 : "A" ,   1 : "B" ,   2 : "C" , }; renderData (arrayAdapter (data)); 
外观模式 1. 定义 为子系统中的一组接口提供一个一致的界面,定义一个高层接口,这个接口使子系统更加容易使用
2. 核心 可以通过请求外观接口来达到访问子系统,也可以选择越过外观来直接访问子系统
3. 实现 外观模式在 JS 中,可以认为是一组函数的集合
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 function  start (  console .log ("start" ); } function  doing (  console .log ("doing" ); } function  end (  console .log ("end" ); } function  execute (  start ();   doing ();   end (); } function  init (     execute (); } init ();