几种常用的设计模式(JS精简版)

单例模式(Singleton)

该模式应该算是最常用的一种设计模式,它提供了一种将代码组织为一个逻辑单元的手段,这个逻辑单元中的代码可以通过单一的变量进行访问。它可以减少页面中全局变量的个数,让代码逻辑更加清晰。

  • 应用
    网页的弹窗,全局loading等

  • 命名空间

var myNamespace = {
    p1:123,
    p2:'test',
    add(){},
    remove(){}
}
  • 惰性加载
    即通过一个静态方法来检查对象是否已经被实例化,若没有,则创建实例并返回,否则直接返回现有实例。
class Person {
    constructor(){
        this.instance = null;
    }
    static getInstance() {
        if(!this.instance) {
            this.instance = new Person();
        }
        return this.instance;
    }
}

发布/订阅模式(Publish/Subscribe)

简单来说,就是事件监听,类似document.body.addEventListener('click',fn)

  • 简单实现
var event = {
  listener: {},
  on(key, fn) {
    if (!this.listener[key]) {
      this.listener[key] = [];
    }
    this.listener[key].push(fn);
  },
  emit(key, ...others) {
    var fnPool = this.listener[key];
    if (!fnPool || fnPool.length === 0) {
      return false;
    }
    for (var i = 0, fn; fn = fnPool[i++];) {
      fn.apply(this, others);
    }
  },
  remove(key, removeFn) {
    var fnPool = this.listener[key];
    if (!fnPool || fnPool.length === 0) {
      return false;
    }
    if (!removeFn) {
      fnPool && (fnPool.length = 0);
    } else {
      for (var i = 0, fn; fn = fnPool[i]; i++) {
        if (fn === removeFn) {
          fnPool.splice(i, 1);
        }
      }
    }
  }
};

event.on('test', function (a, b) {
  console.log(a + b)
})

setTimeout(() => {
  event.emit('test', 1, 8)
}, 5000)
  • jquery实现
    jQuery.Callbacks( flags )

迭代器模式(Iterator)

该模式就是提供一个方法按照顺序存取一个对象中的各个元素,且迭代过程完全与业务逻辑分离。

1 内部迭代
类似forEach,$.map等等
2 外部迭代
类似es6中提供的Iterator接口
3 应用(登录验证)

function isNumber(){}
function isBoundMaxLength(){}
function isEmpty(){}
function iteratorValidator(...args){
    return args.every(fn=>fn !== false)
}

var shouldLogin = iteratorValidator(isNumber(),isBoundMaxLength(),isEmpty())

实际上述实现同样可以用策略模式

策略模式(Strategy)

定义一组算法,将每个算法都封装起来,并且使他们之间可以互换。简言之,将完成一个任务中的各个方法(策略)独立出来,根据不同条件选择不同方法。

  • 实现
let config = new Map([
    ['first_name', 'isNonEmpty'],
    ['age', 'isNumber'], 
    ['username', 'isAlphaNum']
]);

class Checker {
  constructor(check, instructions) {
    [this.check, this.instructions] = [check, instructions];
  }
}

class Validator {
  constructor(config) {
    [this.config, this.messages] = [config, []];
  }

  validate(data) {
    for (let [k, v] of data.entries()) {
      let type = this.config.get(k);
      let checker = Validator[type];
      if (!type) continue;
      if (!checker) throw new Error(`No handler to validate type ${type}`);
      let result = checker.check(v);
      if (!result) this.messages.push(checker.instructions + ` **${v}**`);
    }
  }

  hasError() {
    return this.messages.length !== 0;
  }
}

Validator.isNumber = new Checker((val) => !isNaN(val), 'the value can only be a valid number');
Validator.isNonEmpty = new Checker((val) => val !== "", 'the value can not be empty');
Validator.isAlphaNum = new Checker((val) => !/^a-z0-9/i.test(val), 'the value can not have special symbols');

let validator = new Validator(config);
let data = new Map([
    ['first_name', 'Super'],
    ['last_name', 'Man'], 
    ['age', 'unknown'],
    ['username', 'o_O']
]);
validator.validate(data);
console.log(validator.messages.join('\n')); //the value can only be a valid number **unknown**

适配器模式

定义:将一个类(对象)的接口(方法或属性)转化成使用者希望的另外一个接口(方法或属性),使得原接口不兼容的类(对象)可以正常使用,即相当于增加一道兼容层

class Test {
    fn(){}
}

class TestA {
    fnA(){
    }
}

class Aadaptee extends TestA{
    constructor(){
        super()
    }
    fn(){
        return this.fnA()
    }
}

// const test = new Test()
// test.fn()

const test = new Aadaptee()
test.fn()

参考