text: js设计模式
  设计模式是为了更好的代码复用、可读、可靠、可维护。1、单一职责原则（SRP）[Single Responsibility Principle]     一个对象（方法）只做一件事情2、里氏替换原则    子类可以扩展父类的功能，但不能改变父类原有的功能3、依赖倒置原则      高层模块不应该依赖低层模块，二者都应该依赖其抽象。抽象不应该依赖细节，细节应该依赖抽象。(就是将公共的业务逻辑抽象出来)4、接口隔离原则      在一个类中尽量少公布public方法，接口是对外的承诺，承诺越少对系统的开发越有利，变更的风险也就越少，同时也有利于降低成本5、合成复用原则     尽量使用对象组合/聚合，而不是继承关系达到软件复用的目的6、最少知识原则     减少对象（方法、系统、模块等）之间的联系       定义：保证一个类仅有一个实例，并提供一个访问它的全局访问点。       一个标准的单例模式是用一个变量来标志当前是否已经为某个类创建过对象，如果是，则在下一次获取该类的实例时，直接返回之前创建的对象。1.1、单例模式的应用      定义：定义一系列的算法，把它们一个个封装起来，并且使它们可以相互替换。2.1、使用策略模式计算奖金公司的年终奖是根据员工的工资基数和年底绩效情况来发放的，假设财务部要求我们提供一段代码，来方便他们计算员工的年终奖。例如：- 绩效为 4.0 的人年终奖有 4 倍工资（S）- 绩效为 3.75 的人年终奖有 3 倍工资（A）- 绩效为 3.5 的人年终奖是 2 倍工资（B）- 绩效为 3.25 的人年终奖是 0 倍工资（C）使用组合函数重构代码:  把各种算法封装到一个个的小函 数里面，这些小函数有着良好的命名，可以一目了然地知道它对应着哪种算法，它们也可以被复用在程序的其他地方。  使用策略模式重构代码  策略模式定义回顾：一系列的算法，把它们一个个封装起来。将不变的部分和变化的部分隔开。  在这个例子里，算法的使用方式是不变的，都是根据某个算法计算奖金数额。但是算法的实现是各异和变化的，每种绩效对应着不同的计算规则。以上是基于面向对象模拟的策略模式，虽然条理清晰符合策略模式的基本原则，但是代码还是不够简洁。  一个基于策略模式的程序至少由两部分组成：  第一个部分是一组策略类，策略类封装了具体的算法，并负责具体的计算过程。  第二个部分是使用类，用来调用封装的策略类2.2、使用策略模式完成表单校验一个注册的页面，在点击注册按钮之前，有如下几条校验逻辑：1. 用户名不能为空。2.  密码长度不能少于 6 位。 3. 手机号码必须符合格式。以上代码存在的问题：1. registerForm.onsubmit 函数比较庞大，包含了很多 if-else 语句，这些语句需要覆盖所有的校验规则。 2.  registerForm.onsubmit 函数缺乏弹性，如果增加了一种新的校验规则，或者想把密码的长 度校验从 6 改成 8，我们都必须深入 registerForm.onsubmit 函数的内部实现，这是违反开放—封闭原则的。 3.  复用性差用策略模式重构表单校验第一步我们要把这些校验逻辑都封装成策略对象第二步实现 Validator 类1、创建一个Validator类 `const validator = new Validator()`2、Validator需要提供一个方法把校验字段和规则绑定3、开始校验4、返回校验结果     定义：为一个对象提供一个代用品或占位符，以便控制对它的访问3.1、小明暗恋小花的故事       快过520了，小明想给小花送一个礼物，但是小明第一次给喜欢的人送礼物有点不好意思，于是打听到他们之间有个共同好友小天，小明决定让小天帮他完成送礼物这件事        小明跟小花刚刚认识两天，还无法辨别小花什么时候心情好。如果不合时宜地把礼物送给小花，礼物被直接扔掉的可能性很大，这个礼物可是小明吃了 7 天泡面换来的。 但是小花的朋友小天 却很了解她，所以小明只管把礼物交给小天，小天会监听小花的心情变化，然后选 择小花心情好的时候把礼物转交给她以上可以看到，小天可以帮小花过滤一些非必要的请求，这种就叫做`保护代理`。另外，假设现实中的礼物价格不菲，导致在程序世界里，new Gift 也是一个代价昂贵的操作， 那么我们可以把 new Gift 的操作交给代理 小天去执行，小天会选择在小花心情好时再执行 new Gift，这是代理模式的另一种形式，叫作`虚拟代理`。3.2、虚拟代理实现图片预加载通过 proxyImage 间接地访问 MyImage。proxyImage 控制了客户对 MyImage 的访问，并 且在此过程中加入一些额外的操作，比如在真正的图片加载好之前，先把 img 节点的 src 设置为 一张本地的 loading 图片。3.3、代理的意义不用代理的预加载图片函数实现如下：       根据面向对象设计的原则——单一职责原则，一个类（通常也包括对象和函数等）而言，应该仅有一个引起它变 化的原因。如果一个对象承担了多项职责，就意味着这个对象将变得巨大，引起它变化的原因可 能会有多个。如果一个对象承担的职责过多， 等于把这些职责耦合到了一起，这种耦合会导致脆弱和低内聚的设计。当变化发生时，设计可能 会遭到意外的破坏。       以上代码中MyImage 对象除了负责给 img 节点设置 src 外，还要负责预加载图片。违反单一职责原则，同时违反开放— 封闭原则。例如5 年后的网速快到根本不再需 要预加载，我们可能希望把预加载图片的这段代码从 MyImage 对象里删掉。这时候就不得不改动 MyImage 对象了。于是代理的作用在这里就体现出 来了，代理负责预加载图片，预加载的操作完成之后，把请求重新交给本体 MyImage。就算有一天我们不再需要预加载， 那么只需要改成请求本体而不是请求代理对象即可。 3.4、虚拟代理合并 HTTP 请求        在一段时间内有多个相同的http请求被发出，用代理模式将请求参数整合后再发送请求3.5、其他代理      - 防火墙代理      - 远程代理      - 智能引用代理      - 写时复制代理      - 缓存代理4.1、小明买房       小明最近看上了一套房子，到了售楼处之后才被告知，该楼盘的房子早已售罄。好在售楼 小红 告诉小明，不久后还有一些尾盘推出，开发商正在办理相关手续，手续办好后便可以购买。 但到底是什么时候，目前还没有人能够知道。 于是小明记下了售楼处的电话，以后每天都会打电话过去询问是不是已经到了购买时间。除 了小明，还有小强、小龙也会每天向售楼处咨询这个问题。一个星期过后，售楼 小红 决 定辞职，因为厌倦了每天回答 1000 个相同内容的电话。       之后售楼部改进工作流程，把他们电话号码留在 了售楼处。售楼 小丽 答应他，新楼盘一推出就马上发信息通知小明。小强和小龙也是一 样，他们的电话号码都被记在售楼处的花名册上，新楼盘推出的时候，售楼小丽会翻开花名册， 遍历上面的电话号码，依次发送一条短信来通知他们。       小明只想买 88 平方米的房子，但是发布者把 110 平 方米的信息也推送给了小明，这对小明来说是不必要的困扰。所以我们有必要增加一个标示 key， 让订阅者只订阅自己感兴趣的消息。改写后的代码如下：       小明突然不想买房子了，为了避免继续接 收到售楼处推送过来的短信，小明需要取消之前订阅的事件4.2、网站登录        网站里有 header 头部、nav 导航、消息列表、购物车等模块。这几个模块的渲染有一个共同的前提条件，就是必须先用 ajax 异步请求获取用户的登录信息。        现在登录模块我们必须了解 header 模块里设置头像的方法叫 setAvatar、购物车模块里刷新的方法叫 refresh，这种耦合性会使程序变得僵硬，header 模块不 能随意再改变 setAvatar 的方法名，针对具体实现编程是很不好的。      用发布-订阅重构之后      各模块监听登录成功的消息：4.3、全局的发布-订阅        发布—订阅模式可以用一个全局的 Event 对象来实现，订阅者不需要了解消 息来自哪个发布者，发布者也不知道消息会推送给哪些订阅者，Event 作为一个类似“中介者” 的角色，把订阅者和发布者联系起来。见如下代码：