常见的设计模式在JavaScript中的应用:单例模式、工厂模式、组合模式、观察者模式、代理模式

单例模式

单例模式是指在内存中只会创建且仅创建一次对象的设计模式。在程序中多次使用同一个对象且作用相同时,为了防止频繁地创建对象使得内存飙升,单例模式可以让程序仅在内存中创建一个对象,让所有需要调用的地方都共享这一单例对象。

  • 构建一个函数,返回一个对象实例
  • 用一个声明一次的变量来控制这个对象实例的生成
  • 如果这个变量里面已经存了一个对象则直接返回,如果没有则生成一个对象

闭包实现

function singleClosure() {
        let obj;
        return function () {
          if (!obj) {
            obj = new Object();
          }
          return obj;
        };
}

原型实现

function singlePrototype() {
        if (!Object.prototype.instance) {
          Object.prototype.instance = new Object();
        }
        return Object.prototype.instance;
      }

static实现

function singleStatic() {
        if (!Object.instance) {
          Object.instance = new Object();
        }
        return Object.instance;
      }

全局变量实现

不推荐,因为window对象只有浏览器有,非浏览器的global(全局对象)不是window
function singleWindow() {
        if (!window.instance) {
          window.instance = new Object();
        }
        return window.instance;
}

工厂模式

工厂模式:以一个工厂方法来生产对应的对象。

1.手动构建对象

2.手动给对象设置属性

3.手动返回对象

 function factory() {
        let obj = new Object();
        obj.name = 'jack';
        obj.age = '18';
        return obj;
}

组合模式*

组合多个对象形成树形结构以表示“整体-部分”的关系的层次结构。组合模式对叶子节点和容器节点的处理具有一致性,又称为整体-部分模式,使得用户对单个对象和组合对象的使用具有一致性。

将多个相同名字的方法,放在一个地方统一调用,比如下面创建了三个类,他们的实例对象都包含say方法
      class SayHello {
        constructor() {}
        say() {
          console.log('hello');
        }
      }
      class SayHi {
        constructor() {}
        say() {
          console.log('hi');
        }
      }
      class SayGoodBye {
        constructor() {}
        say() {
          console.log('good bye');
        }
      }
以上的三个类分别都具备一个say方法,如果需要调用的话那么是用一个个的对象分别进行调用,而不能统一调用,如果我需要他统一调用,这个时候我们就可以使用组合模式。
      class Combiner {
        constructor() {
          this.objs = [];
        }
        push(obj) {
          this.objs.push(obj);
        }
        excute(fnName) {
          this.objs.forEach((item) => {
            item[fnName]();
          });
        }
      }

      let combiner = new Combiner();
      combiner.push(new SayHello());
      combiner.push(new SayHi());
      combiner.push(new SayGoodBye());
      combiner.excute('say'); //打印:hello  hi  good bye
Vue中的use方法就是用的组合模式实现,该方法是用来安装vue插件,该方法内部会集中调用插件提供的install方法。下面是简单的代码模拟:
      class Vue {
        constructor() {
          //容器来保存对应的对象
          this.objs = [];
        }
        use(obj) {
          this.objs.push(obj);
          this.excute();
        }
        excute() {
          //执行对应的方法
          this.objs.forEach((item) => {
            item['install']();
          });
        }
      }

观察者模式*

观察者模式(obServer)他又被称为发布-订阅者模式,消息模式等。它定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态变化时,会通知所有的观察者对象,使他们能够自动更新自己。
 
事件就是一种观察者模式
  1.事件监听
  2.处理函数执行(js引擎)
  3.取消事件监听
      // 观察者应该具备三个的对应的方法(1.发布事件 2.执行处理函数  3.取消事件)
      class ObServer {
        constructor() {
          //事件和对应的处理函数的存储容器
          this.arg = {}; //{click:[fn1,fn2]}
        }
        //监听事件 参数:事件名,处理函数
        on(eventName, fn) {
          if (!this.arg[eventName]) {
            this.arg[eventName] = [];
          }
          this.arg[eventName].push(fn);
        }
        // 执行处理函数
        emit(eventName, params) {
          if (!this.arg[eventName]) {
            return;
          }
          // 将里面的处理函数都执行
          this.arg[eventName].forEach((fn) => {
            // 将参数传入执行
            fn.call(this, params);
          });
        }
        // 取消事件
        off(eventName, fn) {
          if (this.arg[eventName].length == 1) {
            delete this.arg[eventName];
          } else {
            for (let i; i < this.arg[eventName].length; i++) {
              if (Object.is(this.arg[eventName][i], fn)) {
                this.arg[eventName].splice(i, 1);
                break;
              }
            }
          }
        }
      }
      let obServer = new ObServer();
      obServer.on('click', function (param) {
        console.log('执行了点击' + param);
      });
      function handlerClick(param) {
        console.log('二次处理点击' + param);
      }
      obServer.on('click', handlerClick);
      obServer.off('click', handlerClick);
      obServer.emit('click', 'hello');
在emit方法传入参数传到对应的on里面的处理函数,vue里面子组件传值给父组件实现就是利用了这个原理,儿子通过emit去传值,父亲通过on去接收值

代理模式*

所谓代理模式是指并不直接调用实际的对象,而是通过调用代理对象,来间接的调用实际的对象。通俗的来讲代理模式就是我们生活中常见的中介。

 es7新增了一个类叫 Proxy 他就是用于代理的,可以通过Proxy来访问目标对象的属性和方法,可以理解成,在目标对象之前架设一层“拦截”,外界对该对象的访问,都必须先通过这层拦截,因此提供了一种机制,可以对外界的访问进行过滤和改写。它是vue3的底层实现。
      // 目标对象
      let target = { name: '张三', age: 18 };

      // 利用proxy生成代理对象
      let proxy = new Proxy(target, {

        //参数:目标对象 属性名 代理对象
        get(target, property, proxy) {
          //访问值的时候调用
          if (property == 'name') {
            return '我的名字是' + target[property];
          }
          if (property == 'age') {
            return '我的年纪是' + target[property];
          }
        },

        //参数:目标对象 属性名 属性值 代理对象
        set(target, property, value) {
          // 设置值的时候调用
          target[property] = value;
        },

        deleteProperty(target, property, proxy) {
          // 删除属性的时候调用
          delete target[property];
        },

        has(target, property) {
          // 的时候调用 必须返回boolean类型
          console.log('has调用了');
          return property in target;
        },

        apply(target, property) {
          // 函数调用的时候触发
        },
      });
      
      console.log(proxy.age); //调用get
      proxy.name = 'jack'; //调用set
      console.log(proxy);
      console.log('name' in proxy); //调用has 返回boolean值
      delete proxy.name; //调用deleteProperty
      console.log(proxy);

适配器模式

又叫做变压器模式,就是用来做适配,它将不兼容的接口转换为可兼容的接口,让原本由于接口不兼容而不能一起工作的类可以一起工作。

      let phone = {
        fn() {
          return '5v';
        },
      };
class Target { constructor() {} fn() { let v
= phone.fn(); return '200转换为' + v; } } new Target().fn();

 

posted @ 2022-08-24 19:43  Lamb~  阅读(14)  评论(0编辑  收藏  举报