JavaScript 设计模式从零开始(上

JavaScript 设计模式从零开始(上

简介: 本文主要讲单例模式,策略模式,代理模式,本文内容均参考曾探所著《Javascript设计模式与开发实践一书》

1、单例模式

单例模式的定义是: 保证一个类只有一个实例,并提供一个全局访问它的全局访问点
创建单例模式的思路是:使用一个变量来记录这个对象是否已经被创建过,如果已经创建则直接返回这个对象
标准单例模式

var Singleton = function(name){
  this.name = name
}
Singleton.prototype.getName = function(){
  return this.name
}

Singleton.getInstance = function(name){
  if(!this.instance){
    this.instance = new Singleton(name)
  }

  return this.instance
}

var a = Singleton.getInstance('single1')
var b = Singleton.getInstance('single2')

console.log(a === b)

或者通过闭包创建

var Singleton = function(name){
  this.name = name
}
Singleton.prototype.getName = function(){
  return this.name
}

Singleton.getInstance = (function(name){
  var instance = null
  if(!instance){
    instance = new Singleton(name)
  }

  return instance
})()

var a = Singleton.getInstance('single1')
var b = Singleton.getInstance('single2')

console.log(a === b)

通用惰性单例

//创建单例的函数
var getSingle = function(fn){
	var result
	return function(){
		return resulr || (result = fn.apply(this,arguments))
	}
}

//创建单个弹窗 以fn参数的形式传入 getSingle
var createLoginLayer = function(){
  var div = document.createElement('div')
  div.innerHTML = "我是登录浮窗"
  div.style.display = "none"
  document.body.appendChild(div)
  return div
}

var createSingleLoginLayer = getSingle(createLoginLayer)

let loginButton = document.createElement('button')
loginButton.innerHTML = "登录"
loginButton.id = "login-button"
document.body.appendChild(loginButton) 
//点击登录按钮 创建登录浮窗
document.getElementById('login-button').onclick =  function(){
  var loginLayer = createSingleLoginLayer()
  loginLayer.style.display = "block";
}

利用上面的例子创建单例的iframey也很方便

2 、策略模式

策略模式的定义是: 定义一系列的算法,把他们一个一个封装起来,并且可以使他们相互替换。
比如: 播放视频我们可以选择使用flash插件也可以使用HTML5 的video

突然有点想开摆 哈哈 先写完这篇吧,最近要学uniapp 和深入学习一下ts,还有git的博客没有写
心情乱遭遭的

代码实例:计算年终奖金,根据不同的级别发送不同的奖金

//策略对象
const strategies = {
  S: function(salary){
    return salary * 4
  },
  A: function(salary){
    return salary * 3
  },
  B: function(salary){
    return salary * 2
  }
}

let caculateBonus = function(level,salary){
  return strategies[level](salary)
}

console.log(caculateBonus('S',20000));
console.log(caculateBonus('A',10000));

我们一般的表单校验是通过if eles 来实现的
代码示例:用策略模式进行表单校验

//策略模式实现表单校验 strategy.js

let registerForm = document.getElementById('register-form')
let inputName = document.getElementById('user-name')
let inputPassword = document.getElementById('password')
let inputPhone = document.getElementById('phone')


const FormStrategies = {
  isEmpty: function (value, errorMsg) {
    if (value === '') {
      return errorMsg
    }
  },
  minLength: function (value, length, errorMsg) {
    if (value.length < length) {
      return errorMsg;
    }
  },
  isMobile: function (value, errorMsg) {
    if (!/(^1[3|5|8][0-9]{9}$)/.test(value)) {
      return errorMsg;
    }
  }
}

//验证函数
const validateFunc = function () {
  let validator = new Validator() //创建一个validator对象

  validator.add(inputName, 'isEmpty','名字不能为空')
  validator.add(inputPassword, 'minLength:6','密码长度不能小于6') //密码长度不能小于6
  validator.add(inputPhone, 'isMobile','手机格式不正确') //手机号码格式不正确
  let errorMsg = validator.start() //获得校验结果
  return errorMsg
}

//定义 Validator 类
class Validator {
  constructor() {
    this.cache = []
  }
  //定义添加方法
  add(dom, rule, errorMsg) {
    let ary = rule.split(':') //把 strategy 和 参数分开
    this.cache.push(function () { //存储校验函数
      let strategy = ary.shift()
      ary.unshift(dom.value)
      ary.push(errorMsg)
      return FormStrategies[strategy].apply(dom, ary) //调用策略对象校验
    })
  }
  //遍历cache 的规则进行校验
  start() {
    // this.cache.forEach((validateFunc)=>{
    //   let msg = validateFunc()
    //   if(msg){
    //     return msg
    //   }
    // })
    console.log('start validate')
    for (let i = 0; i < this.cache.length; i++) {
      let msg = this.cache[i]()
      if (msg) {
        return msg
      }
    }
  }
}

registerForm.onsubmit = function(){
   //提交表单
   var errorMsg = validateFunc() //校验表单

   if (errorMsg) {
     alert(errorMsg)
     return false; //阻止提交
   }
}

strategy.html

<!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>Strategy 策略模式</title>
</head>
<body>
  <div>

    <form action="http://localhost:8088/register.php" method="post" id="register-form">
      <label for="name">名字:
        <input type="text" placeholder="请输入名字"  name="user_name" value="" id="user-name">
      </label>
      <br>
      <label for="password">密码:
        <input type="password" name="password" id="password" value="" id="password">
      </label>
      <br>
      <label for="phone">手机号码
        <input type="text" placeholder="请输入手机号码" name="phone" value="" id="phone">
      </label>
     <br>
      <input type="submit" value="提交">
    </form>
    
    <script src="./strategy.js"></script>
  </div>
</body>
</html>

php后台代码 可不写
速装一个 wamp 或 xampp
配置系统环境变量
cd ‘./php’ register.php 根目录
php -S localhost:8088

<!DOCTYPE html> 
<html> 
<body> 

<?php 
  echo "Hello World!";
  echo $_POST['user_name'];
  echo $_POST['password'];
  echo $_POST['phone'];
?> 

</body> 
</html>

策略模式优点 避免大量 if eles 重复代码,可复用
缺点 需要封装策略对象,必须对不同 的 strategy有所了解

3、代理模式

代理模式是为一个对象提供一个代用品或占位符 以便控制对它的控制访问
讲到代理模式不由想到 es6 的Proxy 这里提供一个 大佬博客的传送门,有兴趣的可以看看
es6 Proxy

a 虚拟代理
b 缓存代理
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值