前端常见设计模式汇总

49 阅读2分钟

封装的好处:封装的优势在于定义只可以在类内部进行对属性的操作,外部无法指手画脚。 要想修改,也只能通过你定义的封装方法。

一、设计原则

  • 单一职责原则:就一个类而言,只有一个引起它变化的原因。

  • 开放封闭原则:核心的思想是软件实体(类、模块、函数等)是可扩展的、但不可修改的。 即对扩展是开放的,对修改是封闭的。

工厂模式

工厂模式是将逻辑封装在一个函数中不暴露创建对象的具体逻辑。

class Person {
	constructor(name,age,sex) {
		this.name = name;
		this.age = age;
		this.sex = sex;
	}
	sayName(){
		console.log(`我叫 ${this.name},性别 ${this.sex},今年 ${this.age}`);
	}
	
}

	const p1 = new Person('jsliang', 25, '男');
	const p2 = new Person('靓女', 25, '女');
	
	p1.sayName(); // 我叫 jsliang,性别 男,今年 25
	p2.sayName(); // 我叫 靓女,性别 女,今年 25

小结

工厂模式是为了解决对个类似对象声明的问题,也就是为了解决实例化对象产生重复的问题。

工厂模式的优缺点:

  • 优点:能解决对个相似的问题。

  • 缺点:对象的类型不知道。

单例模式

单例模式即一个类只能构造出唯一实例,单例模式的意义在于共享、唯一。 Redux/Vuex 中的 Store、jQuery 的 $ 或者业务场景中的购物车、登录框都是单例模式的应用。

class SingletonLogin {
  constructor(name, password) {
    this.name = name;
    this.password = password;
  }
  static getInstance(name, password) {
    // 判断对象是否已经被创建,若创建则返回旧对象
    if (!this.instance) {
      this.instance = new SingletonLogin(name, password);
    }
    return this.instance;
  }
}

let obj1 = SingletonLogin.getInstance('jsliang', '123456')
let obj2 = SingletonLogin.getInstance('zhazhaliang', '654321')

console.log(obj1 === obj2)    // true
console.log(obj1)           // SingletonLogin { name: 'jsliang', password: '123456' }
console.log(obj2)           // SingletonLogin { name: 'jsliang', password: '123456' }

代理模式和中介者模式

代理模式适用场景:

代理模式的适用场景是图片的预加载,在预加载过程中,图片未加载完毕之前,用一个 loading 作为图片的占位符,等待加载完毕之后再进行赋值。

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width,initial-scale=1.0,maximum-scale=1.0,user-scalable=no">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>代理模式</title>
</head>

<body>
  <div class="animation">动画元素</div>

  <script>
    window.onload = function () {
      var myImage = (function () {
        var imgNode = document.createElement("img");
        document.body.appendChild(imgNode);
        return {
          setSrc: function (src) {
            imgNode.src = src;
          }
        }
      })();
      // 代理模式
      var ProxyImage = (function () {
        var img = new Image();
        img.onload = function () {
          myImage.setSrc(this.src);
        };
        return {
          setSrc: function (src) {
            myImage.setSrc("https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1603709264332&di=f6f8e48c1c88bf640aac9899df98a97c&imgtype=0&src=http%3A%2F%2F5b0988e595225.cdn.sohucs.com%2Fq_mini%2Cc_zoom%2Cw_640%2Fimages%2F20171107%2F643ceb1031394c5887d3509b31878c52.gif");
            setTimeout(() => {
              img.src = src;
            }, 3000);
          }
        }
      })();
      // 调用方式
      ProxyImage.setSrc("https://ss1.bdstatic.com/70cFuXSh_Q1YnxGkpoWK1HF6hhy/it/u=3592308877,3684082784&fm=26&gp=0.jpg");
    };
  </script>
</body>

</html>


发布订阅模式(观察这模式)

当一个对象发生改变时,所有依赖于它的对象都将得到通知。 发布-订阅模式的优缺点:

  • 优点
  1. 支持简单的广播通信。当对象状态发生改变时,会自动通知已经订阅过的对象。

2 . 发布者与订阅者的耦合性降低。我是卖家我并不关心有多少人订阅了, 我只要到货的时候,将货物数量更改下就行了。

  • 缺点
  1. 耗时耗内存。创建订阅者需要消耗一定的时间和内存
  2. 过度使用不好维护。

举个代码小例子,然后讲讲 Vue 中的 Object.defineProperty 和 Proxy 使用。

那么,为什么 Vue 3.0 要换成 Proxy 呢?

Object.defineProperty 缺点:

  1. 不能监听数组变化

  2. 必须遍历对象每个属性 而 Proxy 的目标是对象,这样就省去了属性的遍历。

Proxy观察者模式以及Object.defineProperty的缺点