说说你了解的设计模式

171 阅读3分钟
单例模式:

**好处:**减少全局变量,全局对象被污染问题

实现:

  • 懒汉式

    let ShopCar = (function () {
      let instance;
      function init() {
        /*这里定义单例代码*/
        return {
          buy(good) {
            this.goods.push(good);
          },
          goods: [],
        };
      }
      return {
        getInstance: function () {
          if (!instance) {
            instance = init();
          }
          return instance;
        },
      };
    })();
    let car1 = ShopCar.getInstance();
    let car2 = ShopCar.getInstance();
    car1.buy('橘子');
    car2.buy('苹果');
    console.log(car1.goods); //[ '橘子', '苹果' ]
    console.log(car1 === car2); // true
    
  • 饿汉式

面试题 -> 实现Storage,使得该对象为单例,基于 localStorage 进行封装。实现方法 setItem(key,value) 和 getItem(key)

class Storage {
  static getInstance() {
    if(!Storage.instance) {
      Storage.instance = new Storage()
    }
		return Storage.instance
  }
  getItem(key) {
    return localStorage.getItem(key)
  }
  setItem(key,value) {
    return localStorage.setItem(key,value)
  }
}
Storage.getInstance()

**思想:**一个类只能创建一个实例,判断有没有创建过实例,有创建过则直接返回,否则创建一个实例并返回

懒汉式在类加载时,不创建实例,因此类加载速度快,但运行时获取对象的速度慢;支持延迟加载 饿汉式在类加载时就完成了初始化,所以类加载较慢,但获取对象的速度快

工厂函数:

**好处:**解决了代码复用性问题,减少页面的中的冗余代码。

思想:

  • 入口——函数参数
  • 加工——具体函数功能
  • 出口——函数返回值
// 入口
function createPerson(name, age) {
  //加工过程
    var obj = {};
    obj.name = name;
    obj.age = age;
    obj.info = function () {
        console.log(obj.name, obj.age);
    }
  // 出口
    return obj;
}

var p1 = createPerson('xiaopei' , 26);
p1.info();

var p2 = createPerson('xiaoqiangh' , 25);
p2.info();

console.log(p1.info == p2.info) // false

两个问题:

  • 可读性问题:不知道这个函数具体是要来当什么用的,用于功能函数还是工厂模式。
  • 空间性问题:里面的function 不是通用的,不同的存储空间,每次调用都会创建。
构造模式:

**好处:**解决了工厂模式的可读性

实现:

function CreatePerson(name, age) {
    this.name = name;
    this.age = age;
    this.info = function () {
        console.log(this.name, this.age);
    }
}

var p1 = new CreatePerson('xiaopei' , 26);
p1.info();

var p2 = new CreatePerson('xiaoqiangh' , 25);
p2.info();

console.log(p1.info == p2.info) // false

**问题:**工厂函数的空间问题还存在

原型模式:

**好处:**解决了工厂模式的空间性问题

function CreatePerson() {}
CreatePerson.prototype.name = '';
CreatePerson.prototype.age = 0;
CreatePerson.prototype.play = []
CreatePerson.prototype.info = function () {
    console.log(this.name, this.age,this.play);
}

var p1 = new CreatePerson();
p1.name = 'xiaopei'
p1.play.push('game')
p1.info(); // xiaopei 0 ["game"]

var p2 = new CreatePerson();
p2.name = 'xiaoqiang'
p2.info(); // xiaoqiang 0 ["game"]

console.log(p1.info == p2.info) // true

**问题:**类型为引用类型的时候,对它的增删改都是同一个地址。改一个就等于改多个

混合模式:

好处:即解决了可读性问题,又解决了空间占用问题,

function CreatePerson() {
  this.name = '';
  this.age = 0;
  this.play = []
}

CreatePerson.prototype.info = function () {
    console.log(this.name, this.age,this.play);
}

var p1 = new CreatePerson();
p1.name = 'xiaopei'
p1.play.push('game')
p1.info(); // xiaopei 0 ["game"]

var p2 = new CreatePerson();
p2.name = 'xiaoqiang'
p2.info(); // xiaoqiang 0 []

console.log(p1.info == p2.info) // true

思想:使用构造函数的属性命名方法,原型模式的方式定义方法。

策略模式:

好处:

  • 避免大量冗余的代码判断,比如if else等

**思想:**策略模式将不同算法进行合理的分类和单独封装,让不同算法之间可以互相替换而不会影响到算法的使用者

实现:

// 定义几个策略类
var PaymentMethodStrategy = {
  BankAccount: function (money) {
    return money > 50 ? money * 0.7 : money;
  },
  CreditCard: function (money) {
    return money * 0.8;
  },
  Alipay: function (money) {
    return money;
  },
};
/*环境类*/
var userPay = function (selectedStrategy, money) {
  return PaymentMethodStrategy[selectedStrategy](money);
};
console.log('银行卡支付价格为:' + userPay('BankAccount', 100)); //70
console.log('支付宝支付价格为:' + userPay('Alipay', 100)); //100
console.log('信用卡支付价格为:' + userPay('CreditCard', 100)); //80

参考文章:

前端开发应该了解的 5 种设计模式

设计模式