大部分的解决方案都是在中间加一层。

如何去设计你的功能

设计思路:
需求 => 思考实现需求需要做什么 => 设计有哪些模块 => 整体类怎么设计 => 思考以后更改的可能,重新设计模块(扩展性) => 编写模块,思考提高代码的健壮性、可读性、有无重复代码(复用性)。
image.png

  1. 怎么去设计模块
  2. 怎么用上设计模式

    创建型

    帮助我们更优雅的创建对象。

    工厂模式

    应用场景:大量的创建对象。
    工厂模式就是写一个方法,然后你只需要调用这个方法,就能拿到你要的对象。 ```javascript

// 栗子1 function Factory(type) { switch(type) { case ‘type1’: return new Type1(); case ‘type2’: return new Type2(); case ‘type3’: return new Type3(); default: return Type(); } }

// 栗子2 jQuery (function() { let jQuery = function(selector) { // return new jQuery(); // 会发生死循环 return new jQuery.fn.init(selector); }

// 吧真正要创建的对象,放到原型链上,或者静态属性上。 // 防止直接调用时发生死循环 jQuery.fn = { init: function() {} };

window.$ = jQuery; })();

  1. <a name="VpwQ6"></a>
  2. ## 建造者模式
  3. 应用场景:精细化的构建一个类。<br />把一个复杂的类的各个部分,拆分成独立的类,然后再在最终类里组合到一块。
  4. ```javascript
  5. // 栗子1
  6. // 模块1
  7. function Model1() {}
  8. // 模块2
  9. function Model2() {}
  10. // 最终的使用类
  11. function Final() {
  12. this.model1 = new Model1();
  13. this.model2 = new Model2();
  14. }
  15. // 栗子2 vue2源码
  16. function Vue(optins) {
  17. if (!(this instanceof Vue)) {
  18. warn(`Vue is a constructor and shuld be called with the 'new' keyword`);
  19. } else {
  20. this._init(options);
  21. }
  22. }
  23. // 代码组合 mixin
  24. initMixin(Vue); // 初始化混合
  25. stateMixin(Vue); // 状态混合
  26. eventsMixin(Vue); // 时间系统混合
  27. lifecycleMixin(Vue); // 生命周期混合
  28. renderMixin(Vue); // 渲染系统混合

单例模式

保证一个类全局只有一个实例化对象。
应用场景:

  • 路由
  • vuex
  • redux ```javascript

// 栗子1 function class1() { if (class1.instance) { return class1.instance; } else { this.a = 1; // class1.instance = new class1(); class1.instance = this; } }

class1.instance = null;

// 栗子2 - vue-router let _vue;

function install(vue) { if (install.installed && _vue === vue) { return; }

install.installed = true; _vue = vue; }

// 在 vue.use 中调用 vue.use();

  1. <a name="UuqBx"></a>
  2. # 结构型
  3. 帮助我们优雅的设计代码结构。
  4. <a name="mZTv7"></a>
  5. ## 策略模式
  6. 优化if-else分支<br />新建一个策略对象,将判断分支当成一个一个的策略。
  7. <a name="VmLU0"></a>
  8. ## 状态模式
  9. 当if-else分支过多时。<br />封装状态。
  10. ```javascript
  11. function moveDiv() {
  12. this.status = [];
  13. this.strage = {
  14. top: function() {},
  15. left: function() {},
  16. right: function() {},
  17. bottom: function() {},
  18. };
  19. }
  20. moveDiv.prototype.run = function() {
  21. this.status = Array.prototype.slice.call(arguments);
  22. this.status.forEach(action => {
  23. this.strage[action]();
  24. });
  25. };
  26. let moveObj = new moveDiv();
  27. moveObj.run('left'); // status == ['left']
  28. moveObj.run('left', 'top'); // status == ['left', 'top']

行为型

模块之间行为模式的总结,帮助我们组织模块的行为。

观察者模式

目的:减少对象间的耦合,提高扩展性。
场景:当两个模块直接沟通会增加他们的耦合性时,不好直接调用,这时使用观察者模式解耦。
栗子:

  1. 点击事件
  2. 异步模块 ```javascript

// function observe() { this.message = {}; }

observe.prototype.regist = function(type, fn) { this.message[type] = fn; };

observe.prototype.fire = function(type) { this.messagetype; };

// 转盘 // 初始化HTML模块,转动控制,转动动画,结果模块 let _domArr = []; let _observe = new observe();

// 初始化HTML function htmlInit() { for (let i = 0; i < 10; i++) { let _div = document.createElement(‘div’); _div.setAttribute(‘class’, ‘item’); _domArr.push(_div); } }

// 转动动画 // moveConfig: { moveTime: 0, speed: 1000, } function move(moveConfig) { let nowIn = 0; let removeNum = 9; let timer = setInterval(() => { if (nowIn !== 0) { removeNum = nowIn - 1 }

  1. _domArr[removeNum].setAttribute('class', 'item');
  2. _domArr[nowIn].setAttribute('class', 'item item-on');
  3. nowIn++;
  4. if (nowIn === moveConfig.moveTime) {
  5. clearInterval(timer);
  6. _observe.fire('finish');
  7. }

}, moveConfig.speed); }

// 转动控制 function moveController() { let final = getFinal(); let _circle = Math.floor(final / 10, 0); let _runCircle = 0; let stopNum = final % 10; let _speed = 200;

move({ moveTime: 10, speed: _speed, });

object.regist(‘finish’, function() { let _time = 0; _speed -= 50; if (_runCircle <= _circle) { _time = 10; } else { _time = stopNum; }

  1. move({
  2. moveTime: _time,
  3. speed: _speed,
  4. });

}); }

// 结果模块 function getFinal() { let _num = Math.random() * 10 + 40; return Math.floor(_num, 0); }

  1. <a name="WPeFM"></a>
  2. # 技巧型
  3. 帮助我们优化代码的技巧。
  4. <a name="5ANTz"></a>
  5. ## 装饰者模式
  6. 目的:不重写方法的扩展方法。<br />场景:当一个方法需要扩展,按时又不能修改原方法。<br />三步走:提取原方法,调用原方法,加入新方法。<br />在不入侵老代码的前提下,修改老代码的实现。<br />栗子:
  7. 1. 代码是以前的老代码。
  8. 1. 要修改的方法是第三方库的方法。
  9. 1. 方法时原生方法。
  10. ```javascript
  11. // dom 绑定的事件,只有操作,没有提示。
  12. function decorator(dom, fn) {
  13. if (typeof dom.onclick === 'function') {
  14. let _old = dom.onclick;
  15. dom.onclick = function() {
  16. _old.call(this);
  17. fn.call(this);
  18. }
  19. }
  20. }
  21. // 为删除按钮扩展新方法
  22. decorator(deleteDom, function() {
  23. alert('删除成功!');
  24. });
  25. // vue -----------------------
  26. // 数组的改变触发渲染
  27. let arr = ['push', 'pop', 'shift'];
  28. let arrayPrototype = Array.prototype;
  29. let arrayCopy = Object.create(arrayPrototype);
  30. arr.forEach(methods => {
  31. arrayCopy[methods] = function() {
  32. let _old = arrayPrototype[methods];
  33. _old.apply(this, argumennts);
  34. // Vue 中触发数据绑定
  35. dep.notify();
  36. }
  37. });

享元模式

把不同部分作为一个享元提取。
目的:减少对象/代码数量
场景:当代码中创建了大量类似对象和类似的代码块

  1. $.extend({a: 1});
  2. $.extend({a: 1}, {b: 2});
  3. // 普通实现,有重复代码
  4. $.extend = function() {
  5. if (arguments.length === 1) {
  6. for (let item in arguments[0]) {
  7. this[item] = arguments[0][item];
  8. }
  9. } else if (arguments.length === 2) {
  10. for (let item in arguments[1]) {
  11. arguments[0][item] = arguments[1][item];
  12. }
  13. }
  14. }
  15. // 享元模式
  16. $.extend = function() {
  17. let source = arguments[0];
  18. let target = this;
  19. if (arguments.length === 2) {
  20. source = arguments[1];
  21. target = arguments[0];
  22. }
  23. for (let item in source) {
  24. target[item] = source[item];
  25. }
  26. }