基于策略模式简单实现element表单校验

什么是策略模式

在策略模式中定义了一系列算法,将每一个算法封装起来,并让他们可以互相替换。策略模式让算法独立于使用它的客户而变化,也称为政策模式。策略模式是一种对象行为型模式。

策略模式的优点:

  • 策略模式利用组合、委托和多态等技术思想,可以有效的避免多种条件选择语句
  • 策略模式提供了对开放封闭原则的完美支持,将算法封装在独立的strategy中,使得它易于切换,易于理解,易于拓展
  • 策略模式中的算法也可以服用在系统的其他地方,从而避免许多重复的复制黏贴工作
  • 在策略模式利用组合和委托来让Context拥有执行算法的能力,这也是i继承一种更轻便的替代方按

缺点:

  • 编写难度加大,代码量变多,这是最直观的一个缺点,但也算不上缺点,毕竟不能以代码量多少衡量代码质量
  • 首先,使用策略模式会在程序中增加许多策略类或者策略对象,但实际上这比把它们负责的逻辑堆砌在Content中要好
  • 其次要使用策略模式,必须了解所有的strategy,必须了解各个strategy之间的不同点,这样才能选择一个合适的strategy。这是违反最少知识原则的

现在我们有一个表单校验需求,在提交按钮之前,有如下几条校验规则:

  • 账号不能为空
  • 密码长度最少7位

一开始我可能会这么写

<template>
  <div>
    <el-form ref="form" :model="form" label-width="80px">
  <el-form-item label="账号">
    <el-input v-model="form.account"></el-input>
  </el-form-item>
  <el-form-item label="密码">
    <el-input type="textarea" v-model="form.passowrd"></el-input>
  </el-form-item>
  <el-form-item>
    <el-button type="primary" @click="onSubmit">登录</el-button>
  </el-form-item>
</el-form>
  </div>
</template>
<script>
export default {
  data(){
    return {
      form: {
          account: '',
          passowrd: '' 
        },
    }
  },
  methods:{
    onSubmit(){
      let {account,passowrd} = this.form;
      if(!account){
        this.$message.error('请输入账号')
      }else if(passowrd.length<7){
        this.$message.error('密码长度不能低于7位')
      }else{
        this.$message.success('表单校验成功')
      }
    }
  }
}
</script>

这是一种很常见的编码方式,但它有很明显的缺点:

  • 包含了很多if语句,这些语句要覆盖所有的校验规则。
  • 若校验规则有变,需要改动onSubmit校验规则,违反开闭原则
  • 算法复用性差
下面让我们使用策略模式重构表单校验
<template>
  <div>
    <el-form ref="form" :model="form" label-width="80px">
  <el-form-item label="账号">
    <el-input v-model="form.account"></el-input>
  </el-form-item>
  <el-form-item label="密码">
    <el-input type="textarea" v-model="form.passowrd"></el-input>
  </el-form-item>
  <el-form-item>
    <el-button type="primary" @click="onSubmit">登录</el-button>
  </el-form-item>
</el-form>
  </div>
</template>
<script>
export default {
  data(){
    return {
      form: {
          account: '',
          passowrd: '' 
        },
        strategies:{
          isNoEmpty(data, key){
            return new Promise((resolve,reject)=>{
              if(data[key]){
                resolve()
              }else{
                reject('请输入账号')
              }
            })
          },
          minLength(data,key){
            return new Promise((resolve,reject)=>{
              if(data[key].length<7){
                reject('密码最低不能少于7个字')
              }else{
                resolve()
              }
            })
          }
        }
    }
  },
  methods:{
    onSubmit(){
      let {strategies} = this;
      strategies.isNoEmpty(this.form,'account')
      .then(()=>strategies.minLength(this.form,'passowrd'))
      .then(()=>{
        this.$message.success('表单校验成功')
      }).catch(err=>{
        this.$message.error(err)
      })
    }
  }
}
</script>

让我们把上面代码优化下,实现简单的element表单校验

<template>
  <div>
    <el-form ref="form" :model="form" label-width="80px">
  <el-form-item label="账号">
    <el-input v-model="form.account"></el-input>
  </el-form-item>
  <el-form-item label="密码">
    <el-input type="textarea" v-model="form.passowrd"></el-input>
  </el-form-item>
  <el-form-item>
    <el-button type="primary" @click="onSubmit">登录</el-button>
  </el-form-item>
</el-form>
  </div>
</template>
<script>
export default {
  data(){
    return {
      form: {
          account: '',
          passowrd: '' 
        },
        rules:{
          account:[
            {methodName:"isNoEmpty",message:'请输入账号'}
          ], 
          passowrd:[
            {methodName:"isNoEmpty",message:'请输入密码'},
            {methodName:"minLength",length:7,message:'密码最低不能少于7位'}
          ],
        },
        strategies:{
          minLength(val,err,length){
              if(val.length<length){
                return err;
              }
          },
          isNoEmpty(val,err){
            if(!val){
              return err;
            }
          }
        }
    }
  },
  methods:{
    strategiesFun(data){
      let {strategies,rules} = this;
      let err = []
      for(let key in data) {
        rules[key].forEach(item=>{
          let _err = strategies[item.methodName](data[key],item.message,item.length);
          _err && err.push(_err);
        });
      }
      return new Promise((resolve,reject)=>{
        err.length ? reject(err[0]) : resolve()
      })
    },
    onSubmit(){
      this.strategiesFun(this.form)
      .then(()=>{
        this.$message.success('表单校验成功')
      }).catch(err=>{
        this.$message.error(err)
      })
    }
  }
}
</script>

比如,某天新增加一个需求,要求账号长度不小于5位数我们只需要在rules对象中增加一条校验规则就行

rules:{
  account:[
    {methodName:"isNoEmpty",message:'请输入账号'},
    {methodName:"minLength",length:5,message:'账号最低不能少于5位'}
  ], 
  passowrd:[
    {methodName:"isNoEmpty",message:'请输入密码'},
    {methodName:"minLength",length:7,message:'密码最低不能少于7位'}
  ],
},
posted @ 2019-06-08 14:39  我会放电啪啪  阅读(484)  评论(2编辑  收藏  举报