假设我们期望给按钮绑定事件以实现关灯->弱光->强光->关灯的效果
按照一般性思维我们得到了以下代码
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta http-equiv="X-UA-Compatible" content="IE=edge" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Document</title> </head> <body> <button id="button"></button> </body> <script> class Light { constructor(button) { this.button = button; this.currentState = "off"; } initButton() { this.button.onclick = ()=>{ this.pressButton() }; } pressButton() { if (this.currentState === "off") { console.log("弱光"); this.currentState = "weakLight"; } else if (this.currentState === "weakLight") { console.log("强光"); this.currentState = "strongLight"; } else { console.log("无光/关灯"); this.currentState = "off"; } } } let light = new Light(button) light.initButton() </script> </html>
1.不符合开放封闭原则
2.胖函数
3.状态切换不明显
4.切换关系不明确
于是我们便得到了以下代码
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta http-equiv="X-UA-Compatible" content="IE=edge" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Document</title> </head> <body> <button id="button"></button> </body> <script> class Light{ constructor(button){ this.button = button this.offLight = new OffLight(this) this.weakLight = new WeakLight(this) this.strongLight = new StrongLight(this) this.currentStatus = new OffLight(this) } setStatus(newStatus){ this.currentStatus = newStatus } initButton() { this.button.onclick = ()=>{ this.currentStatus.changeState() }; } } class WeakLight{ constructor(light){ this.light = light } changeState(){ console.log('强光'); this.light.setStatus(this.light.strongLight) } } class StrongLight{ constructor(light){ this.light = light } changeState(){ console.log('无光'); this.light.setStatus(this.light.offLight) } } class OffLight{ constructor(light){ this.light = light } changeState(){ console.log('弱光'); this.light.setStatus(this.light.weakLight) } } let light = new Light(button) light.initButton() </script> </html>
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta http-equiv="X-UA-Compatible" content="IE=edge" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Document</title> </head> <body> <button id="button">switch</button> </body> <script> function chain(fn,status){ this.status = status this.fn = fn this.next = null } function offLight(light){ if(light.status === 'offLight'){ console.log('弱光'); light.status = 'weakLight' }else{ this.next.fn.call(this.next,light) } } function weakLight(light){ if(light.status === 'weakLight'){ console.log('强光'); light.status = 'strongLight' }else{ this.next.fn.call(this.next,light) } } function strongLight(light){ if(light.status === 'strongLight'){ console.log('无光'); light.status = 'offLight' }else{ this.next.fn.call(this.next,light) } } chain.prototype.setNextChain = function(chain){ this.next = chain } chain.prototype.changeStatus = function(){ this.fn() } let light = new chain(function(){this.next.fn.call(this.next,this)},'offLight') let offlight = new chain(offLight,'offLight') let weaklight = new chain(weakLight,'weakLight') let stronglight = new chain(strongLight,'strongLight') light.setNextChain(offlight) offlight.setNextChain(weaklight) weaklight.setNextChain(stronglight) button.onclick = ()=>{ light.changeStatus() } </script> </html>