{"action":"opened","issue":{"url":"https://api.github.com/repos/Jouryjc/blog/issues/17","repository_url":"https://api.github.com/repos/Jouryjc/blog","labels_url":"https://api.github.com/repos/Jouryjc/blog/issues/17/labels{/name}","comments_url":"https://api.github.com/repos/Jouryjc/blog/issues/17/comments","events_url":"https://api.github.com/repos/Jouryjc/blog/issues/17/events","html_url":"https://github.com/Jouryjc/blog/issues/17","id":351823913,"node_id":"MDU6SXNzdWUzNTE4MjM5MTM=","number":17,"title":"Javascript之策略模式","user":{"login":"Jouryjc","id":11925053,"node_id":"MDQ6VXNlcjExOTI1MDUz","avatar_url":"https://avatars0.githubusercontent.com/u/11925053?v=4","gravatar_id":"","url":"https://api.github.com/users/Jouryjc","html_url":"https://github.com/Jouryjc","followers_url":"https://api.github.com/users/Jouryjc/followers","following_url":"https://api.github.com/users/Jouryjc/following{/other_user}","gists_url":"https://api.github.com/users/Jouryjc/gists{/gist_id}","starred_url":"https://api.github.com/users/Jouryjc/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Jouryjc/subscriptions","organizations_url":"https://api.github.com/users/Jouryjc/orgs","repos_url":"https://api.github.com/users/Jouryjc/repos","events_url":"https://api.github.com/users/Jouryjc/events{/privacy}","received_events_url":"https://api.github.com/users/Jouryjc/received_events","type":"User","site_admin":false},"labels":[],"state":"open","locked":false,"assignee":null,"assignees":[],"milestone":null,"comments":0,"created_at":"2018-08-18T14:17:04Z","updated_at":"2018-08-18T14:17:04Z","closed_at":null,"author_association":"OWNER","body":"#### 定义\r\n策略模式的定义是定义一系列的算法，把它们一个个封装起来，并且使它们可以相互替换。\r\n\r\n越狱相信大部分都看过，第一部剧中迈克尔设计了两条通往医务室的道路。国庆节、春节回家的方式很多种，我们可以选择飞机、高铁，还可以坐火车、大巴车。\r\n\r\n#### 作用\r\n策略模式最主要的作用是在我们想找一种方式替换太多if else的条件语句，因为条件语句会让程序难以维护，且违反开放-封闭原则。\r\n\r\n#### 举例\r\n根据模式的作用，我们来举例：\r\n```js\r\nvar calculateBonus = function (performanceLevel, salary) {\r\n    if (performanceLevel === 'S') {\r\n        return salary * 4;\r\n    }\r\n    if (performanceLevel === 'A') {\r\n        return salary * 3;\r\n    }\r\n    if (performanceLevel === 'B') {\r\n        return salary * 2;\r\n    }\r\n};\r\n\r\n// test\r\ncalculateBonus('B', 20000);    // 40000\r\ncalculateBonus('A', 6000);    // 18000\r\n```\r\n上面的代码就是我们一开始说的，太多if else条件判断语句，且我们想增加第四种模式，比如'C'时，我们需要修改代码内部，添加如下代码：\r\n```js\r\nif (performanceLevel === 'C') {\r\n    return salary;\r\n}\r\n```\r\n最后这个`calculateBonus`会多么庞大，想想就恶心。下面我们使用策略模式来重构一下代码，模式的目的就是讲算法的使用与算法的实现分离开来。\r\n\r\n一个策略模式的程序至少由两部分组成。第一部分是一组**策略类**，**策略类**封装了具体的算法，并负责具体的计算过程。第二个部分是**环境类context**，Context接受客户的请求。随后把请求**委托**给某一个策略类。\r\n\r\n```js\r\nvar performanceS = function () {};\r\n\r\nperformanceS.prototype.calculate = function (salary) {\r\n    return salary * 4;\r\n};\r\n\r\nvar performanceA = function () {};\r\n\r\nperformanceS.prototype.calculate = function (salary) {\r\n    return salary * 3;\r\n};\r\n\r\nvar performanceB = function () {};\r\n\r\nperformanceS.prototype.calculate = function (salary) {\r\n    return salary * 2;\r\n};\r\n```\r\n```JS\r\nvar Bonus = function () {\r\n    this.salary = null;    // 原始工资\r\n    this.strategy = null;    // 绩效等级对应的策略对象\r\n};\r\n\r\nBonus.prototype.setSalary = function (salary) {\r\n    this.salary = salary;    // 设置员工的原始工资\r\n};\r\n\r\nBonus.prototype.setStrategy = function (salary) {\r\n    this.strategy  = strategy ;    // 设置员工绩效等级对应的策略对象\r\n};\r\n\r\nBonus.prototype.getBonus = function () {    // 取得奖金数额\r\n    return this.strategy.calculate(this.salary);    // 把计算奖金的操作委托给对应的策略对象\r\n};\r\n```\r\n测试代码：\r\n```js\r\nvar bonus = new Bonus();\r\n\r\nbonus.setSalary(10000);\r\nbonus.setStrategy(new PerformanceS());\r\n\r\nconsole.log(bonus.getBonus());    // 40000\r\n\r\nbonus.setStrategy(new PerformanceA());\r\nconsole.log(bonus.getBonus());    // 30000\r\n```\r\n上面的重构代码利用传统的OOP，在JS中，这个重构方式显得太笨拙了。函数也是对象，我们更直接和简洁的做法是把strategy直接定义为函数：\r\n```js\r\nvar strategies = {\r\n    \"S\": function (salary) {\r\n        return salary * 4;\r\n    },\r\n    \"A\": function (salary) {\r\n         return salary * 3;\r\n    },\r\n    \"B\": function (salary) {\r\n         return salary * 2;\r\n    }\r\n};\r\n\r\nvar calculateBonus = function (level, salary) {\r\n    return strategies[level](salary);\r\n};\r\n\r\nconsole.log(calculateBonus('S', 20000));    // 80000\r\nconsole.log(calculateBonus('A', 10000));    // 30000\r\n```\r\n策略模式在前端开发中更常见的使用时封装表单校验。\r\n\r\n#### 优点\r\n* 策略模式提供了对“开放-封闭原则”的完美支持，用户可以在不修改原有系统的基础上选择算法或行为，也可以灵活地增加新的算法或行为。\r\n* 策略模式提供了管理相关的算法族的办法。\r\n* 策略模式提供了可以替换继承关系的办法。\r\n* 使用策略模式可以避免使用多重条件转移语句。\r\n\r\n#### 缺点\r\n* 客户端必须知道所有的策略类，并自行决定使用哪一个策略类。\r\n* 策略模式将造成产生很多策略类，可以通过使用[享元模式]()在一定程度上减少对象的数量。\r\n\r\n#### 小结\r\n本文通过提供接近传统面向对象语言的策略模式，也提供了更适合Javascript语言的策略模式版本。在Javascript语言的策略模式中，策略类往往被函数所替代，这时策略模式就成为一种“隐形”的模式。"}}
{"actor":{"display_login":"Jouryjc"}}