javascript-简单理解设计模式

JS设计模式有很多种

在这里插入图片描述

常见的设计模式

(1): 单例模式(Singleton Pattern)-创建

1: 第一种

// 单例模式(Singleton Pattern),后端用的比较多
// 单例模式创建多少对象就只有一个实例

var SinglePattern = (function(){
   function Single(name) {
     this.name = name;
   }
   return function(name) {
     if(!Single.instance) {
       Single.instance = new Single(name)
     }
     return Single.instance
   }
})()
var obj1 = new SinglePattern("张三")
var obj2 = new SinglePattern("李四")

2:第二种

var SinglePattern = (function(){
  var instance = null;
   function Single(name) {
     this.name = name;
   }
   return function(name) {
     if(!instance) {
      instance = new Single(name)
     }
     return instance
   }
})()
var obj1 = new SinglePattern("张三")
var obj2 = new SinglePattern("李四")

console.log("obj1========",obj1);
console.log("obj2========",obj2);
console.log(obj1 === obj2);

在这里插入图片描述
应用场景:数据一致性

(2): 工厂模式(Factory Pattern)- 创建

1: 第一种

function School(type) {
  var instance = new Object();
  instance.name = type.name;
  instance.age = type.age;
  instance.gender = type.gender;
  return instance;
}
var student = School({name: '学生',age: 10,gender: '男'})
var teacher = School({name: '老师',age: 23,gender: '女'})
console.log("student",student);
console.log("teacher",teacher);

在这里插入图片描述
2:第二种

// 历史
function History(d) { return this.data = d };
// 数学
function Math(d) { return this.data = d };

// 课程工厂

function FactoryPattern(type) {
  var Clazz = null;
  var data = null;
  switch(type) {
    case "history":
      Clazz = History;
      data = "历史"
      break;
    case "math":
      Clazz = Math;
      data = '数学';
      break;
  }
  return new Clazz(data)
}

var c1 = FactoryPattern("history")
var c2 = FactoryPattern("math")
console.log(c1,c2);

在这里插入图片描述
工厂模式应用场景:工厂模式-创建(批量生产对象)

(3): 观察者模式(Observer Pattern)-行为

1: ES5写法

// 依赖收集器
function Dep() {
  this.subs = [] // 数据存储,存储需要订阅的内容,未来方便通知
}
Dep.prototype.addSub = function(sub) {
  this.subs.push(sub)
}
// 事件触发方:通知的行为
Dep.prototype.notify = function() {
  this.subs.forEach(sub => {
    sub.update()
  });
}

// 观察者模式
function Observer(name) {
  this.name = name;
}
Observer.prototype.update = function() {
  console.log(this.name,"检测到了更新");
}


var obj1 = new Observer("小a")
var obj2 = new Observer("小b")

// 创建主题对象,对主题产生订阅
var dep = new Dep()
dep.addSub(obj1)
dep.addSub(obj2)
dep.notify()

在这里插入图片描述

2: ES6写法

// 观察者模式
class Observer {
  constructor(name) {
    this.name = name;
  }
  update() {
    console.log(this.name + "更新了")
  }
}
// 依赖收集器
class Dep {
  constructor() {
    this.subs = []
  }
  addSubs(watcher) {
    this.subs.push(watcher)
  }
  notify() {
    this.subs.forEach(w => {
      w.update()
    })
  }
}
var obj1 = new Observer("小a")
var obj2 = new Observer("小b")
var dep = new Dep()
dep.addSubs(obj1)
dep.addSubs(obj2)
dep.notify()

在这里插入图片描述
Observer 负责视图更新,Dep负责收集依赖和通知,视图和逻辑分离,具备消息订阅功能
应用场景: 消息订阅

附加:手写一个eventsBus
class Bus {
  constructor(){
    this.handlers = {}
  }
  // 实现事件订阅on
  on(name,callback) {
    // 没有就新增
    if(!this.handlers[name]) {
      this.handlers[name] = []
    }
    // 有的话就进行push
    this.handlers[name].push(callback)
  }
  // 实现事件发布emit
  emit(name,...args) {
    if(this.handlers[name]) {
      this.handlers[name].forEach(cb=>{
        cb(...args)
      })
    }
  }
  // 实现事件的销毁off
  off(name,callback) {
    const callbacks = this.handlers[name]
    const index = callbacks.indexOf(callback)
    if(index!=-1) {
      callbacks.splice(index,1)
      delete this.handlers[name]
    }
    console.log("this.handlers",this.handlers);
  }
}

var $bus = new Bus();
var fn1 = function(e) {
  console.log("e",e);
 }
var fn2 = function(e) {
  console.log("e",e);
 }
$bus.on("sendMessage",fn1)
$bus.emit("sendMessage",{id:1,name:"张三"})
$bus.off("sendMessage",fn1)


$bus.on("sendInfo",fn2)
$bus.emit("sendInfo","你好呀!")
$bus.off("sendInfo",fn2)


在这里插入图片描述

(4) 装饰器模式(Decorator Pattern)-结构
// Decorator Pattern 装饰器模式

function Coffee() {
  this.info = "苦咖啡";
}
Coffee.prototype.show = function() {
  console.log(this.info); // 这个this就是构造函数本身
}

// 装饰器 
function CoffeeDecorator(coffee) {
  this.coffee = coffee; // 保存被装饰的对象
}
// 加工外部操作,更加利于加工类的扩展和维护
CoffeeDecorator.prototype.show = function() {
  console.log("糖是甜的呦!");
  this.coffee.show()
}
var co1 = new Coffee();
var coDc = new CoffeeDecorator(co1)
coDc.show()

在这里插入图片描述

(5) 代理模式(Proxy-Pattern)
// 创建代理类

function Coffee() {
  this.info = "苦咖啡"; // 代码不利于维护
}
Coffee.prototype.show = function() {
  console.log(this.info);
}

// 创建代理类
function CoffeeProxy() {
  // 用代理替换文本 不存在本体
  this.coffee = new Coffee()
}
CoffeeProxy.prototype.show = function() {
  console.log("代理的甜");
  this.coffee.show()
}
var cp1 = new CoffeeProxy()
cp1.show()

其实装饰器模式和代理模式很相似,如何选择呢,根据当前是否有装饰着实例,如果没有,就用代理模式创建一个实例

(6): 策略模式(Strategy-Pattern)-行为
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>

  <body>
    <form action="" id="form">
      <input type="text" id="username" placeholder="用户名" /><br />
      <input type="text" id="password1" placeholder="密码" /><br />
      <input type="text" id="password2" placeholder="确认密码" /><br />
      <input type="text" id="phone" placeholder="电话" /><br />
      <button>提交</button>
    </form>
    <script>
      function Validate() {}
      // 四个功能函数, 通过外部 调用rules[名称]获取
      Validate.prototype.rules = {
        // 是否手机号
        isMobile: function (str) {
          var rule = /^1[3,4,5,7,8,9][0-9]\d{8}$/;
          return rule.test(str);
        },
        // 是否必填
        isRequired: function (str) {
          // 除去首尾空格
          var value = str.replace(/(^\s*)|(\s*$)/g, "");
          return value !== "";
        },
        // 最小长度
        minLength: function (str, length) {
          var strLength = str.length;
          return strLength >= length;
        },
        // 是否相等
        isEqual: function () {
          // 可以接收多个参数比较
          var args = Array.prototype.slice.call(arguments);
          // 取首项与后面所有的项比较,如果每个都相等,就返回true
          var equal = args.every(function (value) {
            return value === args[0];
          });
          return equal;
        },
      };
      Validate.prototype.test = function (rules) {
        var v = this;
        var valid; // 保存校验结果
        // 外部传递的规则配置参数rules
        for (var key in rules) {
          // 遍历校验规则对象
          // 数组
          for (var i = 0; i < rules[key].length; i++) {
            // 遍历每一个字段的校验规则
            var ruleName = rules[key][i].rule; // 获取每一个校验规则的规则名
            var value = rules[key][i].value; // 获取每一个校验规则的校验值
            if (!Array.isArray(value)) {
              // 统一校验值为数组类型
              value = new Array(value);
            }
            // ruleName         // 确保this是validate对象
            // [this.password2.value, 6]  || this.password2.value
            var result = v.rules[ruleName].apply(v, value); // 调用校验规则方法进行校验
            if (!result) {
              // 如果校验不通过,就获取校验结果信息,并立即跳出循环不再执行,节约消耗
              valid = {
                errValue: key,
                errMsg: rules[key][i].message,
              };
              break;
            }
          }
          if (valid) {
            // 如果有了校验结果,代表存在不通过的字段,则立即停止循环,节约消耗
            break;
          }
        }
        return valid; // 把校验结果反悔出去
      };

      var formData = document.getElementById("form");
      formData.onsubmit = function () {
        event.preventDefault();
        var validator = new Validate();
        // 验证规则 抽离出来, 便于更为灵活的应用验证器
        // 【使用参数传递:便于扩展】 配置上更加语义化
        //  将规则作为规则名称封装,【提高了复用性】
        //  验证器已经和DOM解耦,只关心规则和数据以及message
        var result = validator.test({
          // 和id一致才能获取
          username: [
            {
              rule: "isRequired",
              value: this.username.value,
              message: "用户名不能为空!",
            },
          ],
          password1: [
            {
              rule: "isRequired",
              value: this.password1.value,
              message: "密码不能为空!",
            },
            {
              rule: "minLength",
              value: [this.password1.value, 6],
              message: "密码长度不能小于6个字符!",
            },
          ],
          password2: [
            {
              rule: "isRequired",
              value: this.password2.value,
              message: "确认密码不能为空!",
            },
            {
              rule: "minLength",
              value: [this.password2.value, 6],
              message: "确认密码长度不能小于6个字符!",
            },
            {
              rule: "isEqual",
              value: [this.password2.value, this.password1.value],
              message: "确认密码与原密码不相同!",
            },
          ],
          isMobile: [
            {
              rule: "isRequired",
              value: this.phone.value,
              message: "手机号不能为空!",
            },
            {
              rule: "isMobile",
              value: this.phone.value,
              message: "手机号格式不正确!",
            },
          ],
        });
        if (result) {
          console.log(result);
        } else {
          console.log("校验通过");
        }
      };
    </script>
  </body>
</html>

策略模式常用于代码的复用性和可扩展性
在这里插入图片描述

(7): 适配器模式(Adaptor-Pattern)-结构

这个我们平常很常见


var xiaomi = {
  view() {
    console.log("显示小米屏幕");
  }
}
var iphone = {
  view() {
    console.log("显示iphone屏幕");
  }
}
// 保证手机的高内聚,所以我们吧后续的功能加到外边
// 调用手机,view的功能封装起来
function use(type) {
  if(type === 'xiaomi'){
    xiaomi.view()
  } else if(type === 'iphone') {
    iphone.view()
  }
}
use("xiaomi")

适配器模式通常用于做代码的兼容

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

lxslxskxs

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

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

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

打赏作者

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

抵扣说明:

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

余额充值