微信小程序——设计模式(单例,状态模式,观察者模式、代理模式、策略模式【表单验证】)

本文介绍了JavaScript中单例模式的两种实现方法,以及状态模式、观察者模式、代理模式和策略模式的应用示例,帮助理解如何在实际项目中运用这些设计模式来优化代码结构和管理对象行为。

1、单例模式

1. 定义

保证一个类仅有一个实例,并提供一个访问它的全局访问点

2. 核心

确保只有一个实例,并提供全局访问

第一种:类

// 单例
let __instance = (() => {
    let instance;
    return (newInstance) => {
        if (newInstance) instance = newInstance;
        return instance;
    }
})();
class bleSdk {
    constructor () {
        if (__instance()) return __instance();
        this.foo = 'bar';
        __instance(this);
 
    }
}

export {
  bleSdk
};

js页面

import {bleSdk} from "../bleSdk"
Page({
  data: {

  },
  onLoad() {      
    let ul = new bleSdk();
    let ul2 = new bleSdk();
    console.log("判断是否为单例",ul === ul2)//true
  },

})

第二种:在某个方法里面使用

function SetManager(name) {
      this.manager = name;
      console.log("初始化类", name)
    }

    SetManager.prototype.getName = function () {
      console.log(this.manager);
    };

    var SingletonSetManager = (function () {
      var manager = null; //使用闭包缓存一个内部变量
      return function (name) {
        if (!manager) {
          manager = new SetManager(name);
        }
        return manager;
      }
    })();

    SingletonSetManager('a').getName(); // a
    SingletonSetManager('b').getName(); // a
    SingletonSetManager('c').getName(); // a

2、状态模式

例子:比如超级玛丽,就可能同时有好几个状态比如 跳跃,移动,射击,蹲下 等,如果对这些动作一个个进行处理判断,需要多个if-else或者switch不仅丑陋不说,而且在遇到有组合动作的时候,实现就会变的更为复杂,这里可以使用状态模式来实现。

 const SuperMarry = (function () {
      let _currentState = [], // 状态数组
        states = {
          jump() {
            console.log('跳跃!')
          },
          move() {
            console.log('移动!')
          },
          shoot() {
            console.log('射击!')
          },
          squat() {
            console.log('蹲下!')
          }
        }

      const Action = {
        changeState(arr) { // 更改当前动作
          _currentState = arr
          return this
        },
        goes() {
          console.log('触发动作')
          _currentState.forEach(T => states[T] && states[T]())
          return this
        }
      }

      return {
        change: Action.changeState,
        go: Action.goes
      }
    })()

    // 调用
    SuperMarry.change(['jump', 'shoot'])
      .go() // 触发动作  跳跃!  射击!
      .go() // 触发动作  跳跃!  射击!
      .change(['squat'])
      .go() // 触发动作  蹲下!

使用es6优化:

class SuperMarry {
  constructor() {
    this._currentState = []
    this.states = {
      jump() {console.log('跳跃!')},
      move() {console.log('移动!')},
      shoot() {console.log('射击!')},
      squat() {console.log('蹲下!')}
    }
  }
  
  change(arr) {  // 更改当前动作
    this._currentState = arr
    return this
  }
  
  go() {
    console.log('触发动作')
    this._currentState.forEach(T => this.states[T] && this.states[T]())
    return this
  }
}
 


//使用
new SuperMarry()
    .change(['jump', 'shoot'])
    .go()                    // 触发动作  跳跃!  射击!
    .go()                    // 触发动作  跳跃!  射击!
    .change(['squat'])
    .go()                    // 触发动作  蹲下!

状态模式的使用场景也特别明确,有如下两点:

  1. 一个对象的行为取决于它的状态,并且它必须在运行时刻根据状态改变它的行为。
  2. 一个操作中含有大量的分支语句,而且这些分支语句依赖于该对象的状态。状态通常为一个或多个枚举常量的表示。

简而言之,当遇到很多同级if-else或者switch的时候,可以使用状态模式来进行简化。

3、观察者模式

class Subject {
  constructor() {
    this.subs = [];
  }
  addSub(sub) { //订阅
    this.subs.push(sub);
    console.log("XX订阅了:",this.subs)
  }
  removeSub(sub) { //移除订阅
    const idx = this.subs.findIndex(i => i === sub);
    if (idx === -1) {
      console.log('不存在该观察者');
      return;
    }
    this.subs.splice(idx, 1);
  }
  notify() { //通知
    this.subs.forEach(sub => {
      sub.update(); // 与观察者原型方法update对应!
    });
  }
}

// 观察人,相当于订阅者
class Observer {
  update() {
    console.log('被动触发:update');
  }
}

export {
  Subject,
  Observer
};

index.js使用:

import {
  Subject,
  Observer
} from "../subObserver"
Page({
  data: {

  },
  onLoad: function () {

    const subject = new Subject();
    const ob = new Observer(); //订阅者一
    const ob2 = new Observer(); //订阅者二
    ob2.update = function () { //修改update方法,实现不同逻辑
      console.log('被动触发:我是修改后的方法');
    }

    subject.addSub(ob);
    subject.addSub(ob2);

    //目标发布消息调用观察者的更新方法了。需要主动调用notify来触发
    subject.notify();
    // 被动触发:update
    // 被动触发:我是修改后的方法

    subject.removeSub(ob2); //移除之后就不触发ob2的update了,不再打印`laifeipeng`
    subject.notify();
    //被动触发:update
    // 不存在该观察者
  },
})

4、代理模式

应用场景:图片的预加载,蓝牙各种回调处理
图片的预加载: 平时由于网络的不佳,导致图片出来前会有一片空白。所以我们限用一张 loading 图片占位,在异步方式加载图片

 onLoad: function () {
    const that = this
    var myImage = function () {
      return {
        setSrc: function (src) {
          that.setData({
            urlSrc: src
          })
          console.log("标志0", src)
        }
      }
    };

    // 代理:加载一个默认的图片占位,等服务器返回了图片url再更新
    var proxyImage = function () {
      const onload = function () {
        setTimeout(() => { //模仿请求服务器
          myImage().setSrc("服务器返回了图片的url"); // this指向img!img加载完成后,将img.src传递给myImage
          console.log("标志1")
        }, 2000)
      }
      return {
        setSrc: function (src) {
          myImage().setSrc(src); // loading      
          onload()
        }
      }
    };
    proxyImage().setSrc("./images/loading.gif")    
  },

5、策略模式

应用场景:表单验证
Validator.js

const strategies = {
    isNonEmpty: function (value, errorMsg) {
        if (value === '') {
            return errorMsg;
        }
    },
    minLength: function (value, length, errorMsg) {
        console.log("最小长度==>", value, length, errorMsg)
        if (value.length < length) {
            return errorMsg;
        }
    },
    maxLength: function (value, length, errorMsg) {
        if (value.length > length) {
            return errorMsg;
        }
    },
    isMobile: function (value, errorMsg) {
        if (!/(^1[3|4|5|6|7|8][0-9]{9}$)/.test(value)) {
            return errorMsg;
        }
    }

};


class Validator {
    constructor() {
        this.cache = [];
        this.strategies = strategies;
    }
    add(value, rule, errorMsg) {
        const dom = {
            value: value
        }
        const ary = rule.split(':');
        this.cache.push(function () {//把匿名方法放到数组里,闭包的示例
            var strategy = ary.shift(); //shift() 方法用于把数组的第一个元素从其中删除,并返回第一个元素的值。
            ary.unshift(dom.value); //unshift() 方法可向数组的开头添加一个或更多元素,并返回新的长度。
            ary.push(errorMsg);
            return strategies[strategy].apply(dom, ary); //调用strategies对象的指定方法对象,并规定在函数对象内部this指向dom元素,ary作为参数传入
        });

    }
    start() {
        let msg
        this.cache.find(item => {//循环运行匿名函数
            msg = item();
            if (msg) return msg
        })
        this.cache = []//清除闭包缓存
        return msg;
    };
}

module.exports = {
    Validator: new Validator()
}

index使用:


import {
  Validator
} from "../Validator"

Page({
  data: {

  },
  onLoad: function () {
    Validator.add("123456", 'minLength: 10', '用户名长度不能小于10位')
    Validator.add("1234567891011", 'maxLength: 10', '用户名长度不能大于10位')
    Validator.add("16603003201", 'isMobile', '用户手机不正确')
    const result = Validator.start() //Validator.start()运行返回 undefined表示验证的内容都正确3
    console.log(result)
    if (result) {
      return
    }
    console.log("你好,您的资料全部正确")
  },

})
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

wy313622821

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值