美文网首页js设计模式
js常用设计模式2-策略模式

js常用设计模式2-策略模式

作者: 青色琉璃 | 来源:发表于2021-01-16 23:48 被阅读0次

在生活中,我们去某个地方,可以走路,骑自行车,坐地铁,坐火箭等等,方案很多。
策略模式的定义:定义一系列算法,把他们一个个封装起来,并且使他们可以相互替换。

1,计算奖金

1.1,根据员工绩效和工资来发奖金。

//策略模式:最初代码实现
var calculateBonus = function (level, salary) {
    if (level === 'S') {
        return salary * 5
    }
    if (level === 'A') {
        return salary * 3
    }
    if (level === 'B') {
        return salary * 2
    }
}
console.log(calculateBonus('S', 4000))
console.log(calculateBonus('B', 2000))

缺点:
calculateBonus 里全是if-else,所有的逻辑都在这里面实现;
calculateBonus缺乏弹性,如果新增一个等级C,那么就不得不修改calculateBonus的代码
复用性差

1.2,javaScript版策略模式

// js版本的策略模式->1.html
var strategies = {
    'S': function (salary) {
        return salary * 5
    },
    'A': function (salary) {
        return salary * 3
    },
    'B': function (salary) {
        return salary * 2
    },
}
var calculateBonus = function (level, salary) {
    return strategies[level](salary)
}
console.log(calculateBonus('S', 4000))
console.log(calculateBonus('B', 2000))

2,表单校验

2.1,实现一个普通的表单校验功能

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>

<body>
    <form action="http://test.com/register" method='post' id="registerForm">
        请输入用户名:<input type="text" name="userName" />
        请输入密码:<input type="text" name="passWord" />
        请输入手机号:<input type="text" name="phoneNumber" />
        <button>提交</button>
    </form>

    <script>
        var registerForm = document.getElementById('registerForm')

        registerForm.onsubmit = function () {
            if (registerForm.userName.value === '') {
                alert('用户名不能为空')
                return false
            }
            if (registerForm.passWord.value.length < 6) {
                alert('密码长度不能小于6位')
                return false
            }
            if (!/(^1[3|5|8][0-9]{9}$)/.test(registerForm.phoneNumber.value)) {
                alert('手机号码格式不正确')
                return false
            }
        }
    </script>
</body>

</html> 

缺点很明显:
所有的逻辑都在registerForm.onsubmit中,包含很多if-else语句
registerForm.onsubmit缺乏弹性
算法复用性差

2.2,策略模式重构表单校验

(1)现在,我们要用策略模式来重构表单校验。首先,我们要把校验逻辑都封装成策略对象:

        // 策略基本完成
        var strategies = {
            isNonEmpty: 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
                }
            },
        }

(2)接下来我们来实现Validator类。Validator类在这里作为Context,负责接收用户的请求并委托给strategy对象。先看一下Validator类对象是如何工作的,这样便于我们编写Validator类的代码:

     //新增方法,统一管理form
        var validataFunc = function () {
            var validator = new Validator()
            validator.add(registerForm.userName, 'isNonEmpty', '用户名不能为空')
            validator.add(registerForm.passWord, 'minLength:6', '密码长度不能小于6位')
            validator.add(registerForm.phoneNumber, 'isMobile', '手机号码格式不正确')

            var errorMsg = validator.start()
            return errorMsg
        }
        
        var registerForm = document.getElementById('registerForm')
        registerForm.onsubmit = function () {
            var errorMsg = validataFunc()
            if (errorMsg) {
                alert(errorMsg)
                return false
            }
        }

(3)可以看到,validator对象时通过add方法添加校验规则,add方法有三个参数:

  • registerForm.passWord:指参与校验的input框
  • 'minLength:6':以冒号隔开的字符串。冒号前面的minLength是校验的策略名,6是需要的参数
  • '密码长度不能小于6位':校验未通过时的错误信息
    最后还需要一个start方法,用来对add进来的内容进行校验,并返回错误信息。如果返回了错误信息,registerForm.onsubmit()方法返回false来阻止表单提交。
        // Validator类在这里作为Context,负责接收用户的请求并发送给strategies
        var Validator = function () {
            this.cache = []
        }
        // add中保存需要处理的函数
        Validator.prototype.add = function (dom, rule, errorMsg) {
            this.cache.push(function () {
                var array = rule.split(':')
                var strategy = array.shift()
                array.unshift(dom.value)
                array.push(errorMsg)
                return strategies[strategy].apply(dom, array)
            })
        }
        Validator.prototype.start = function () {
            for (var i = 0, validatorFunc; validatorFunc = this.cache[i++];) {
                var errorMsg = validatorFunc()
                if (errorMsg) {
                    return errorMsg
                }
            }
        }

2.3,一个文本框可对应多个校验规则

实际上2.2可以实现这个功能,只是不太好看

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>

<body>
    <form action="http://test.com/register" method='post' id="registerForm">
        请输入用户名:<input type="text" name="userName" />
        请输入密码:<input type="text" name="passWord" />
        请输入手机号:<input type="text" name="phoneNumber" />
        <button>提交</button>
    </form>

    <script>
        // 这里主要是为了在一个输入框中匹配多个验证规则;实际上之前的策略可以实现,多写几次就好了
        /*  策略对象  */
        var strategies = {
            isNonEmpty: function (value, errorMsg) {
                if (value === '') {
                    console.log(errorMsg)

                    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
                }
            },
        }


        /* Validator类 */
        var Validator = function () {
            this.cache = []
        }
        // add中保存需要处理的函数
        Validator.prototype.add = function (dom, rules) {
            var self = this
            for (let i = 0, rule; rule = rules[i]; i++) {
                (function (rule) {
                    self.cache.push(function () {
                        var startegyArr = rule.startegy.split(':')
                        var startegy = startegyArr.shift()
                        startegyArr.unshift(dom.value)
                        startegyArr.push(rule.errorMsg)

                        return strategies[startegy].apply(dom, startegyArr)
                    })
                })(rule)

            }
        }
        // 上面写法可以改写成这个
        // Validator.prototype.add = function (dom, rules) {
        //     var self = this
        //     for (let i = 0; i < rules.length; i++) {
        //         self.cache.push(function () {
        //             var rule = rules[i]
        //             var startegyArr = rule.startegy.split(':')
        //             var startegy = startegyArr.shift()
        //             startegyArr.unshift(dom.value)
        //             startegyArr.push(rule.errorMsg)

        //             return strategies[startegy].apply(dom, startegyArr)
        //         })
        //     }
        // }
        Validator.prototype.start = function () {
            for (var i = 0, validatorFunc; validatorFunc = this.cache[i++];) {
                var errorMsg = validatorFunc()
                if (errorMsg) {
                    return errorMsg
                }
            }
        }

        /* 用户代码 */
        var registerForm = document.getElementById('registerForm')

        var validataFunc = function () {
            var validator = new Validator()
            validator.add(registerForm.userName, [{
                startegy: 'isNonEmpty',
                errorMsg: '用户名不能为空',
            }, {
                startegy: 'minLength:3',
                errorMsg: '密码长度不能小于3位',
            }])
            validator.add(registerForm.passWord, [{
                startegy: 'minLength:6',
                errorMsg: '密码长度不能小于6位',
            }])
            validator.add(registerForm.phoneNumber, [{
                startegy: 'isMobile',
                errorMsg: '手机号码格式不正确',
            }])

            var errorMsg = validator.start()
            return errorMsg
        }


        registerForm.onsubmit = function () {
            var errorMsg = validataFunc()
            if (errorMsg) {
                alert(errorMsg)
                return false
            }
        }

    </script>
</body>

</html>

3,策略模式的优缺点

优点:

  • 策略模式利用组合、委托、多态等技术和思想,可以有效地避免多重条件选择语句
  • 策略模式提供了对开放-封闭原则的完美支持,将算法封装在独立的strategy中,使得他们易于切换,易于理解,易于扩展
  • 复用性强
    缺点:
  • 用户在使用策略模式时,需要了解其中所有的细节,strategy要暴露所有实现,违反最少知识原则

相关文章

  • js常用设计模式2-策略模式

    在生活中,我们去某个地方,可以走路,骑自行车,坐地铁,坐火箭等等,方案很多。策略模式的定义:定义一系列算法,把他们...

  • Java 常用设计模式简例

    简述Java常用设计模式 简述Java常用设计模式及设计原则 strate---------策略模式针对接口编程,...

  • 设计模式

    软件开发中常用设计模式和设计原则有哪些? ##设计模式: * 1、简单工厂模式(Factory) * 2、策略模式...

  • Java设计模式——策略模式

    Java设计模式之策略模式 这期分享的模式是策略模式是程序设计中最常用的了,因为开发工作中总是会使用到策略模式。 ...

  • Strategy(策略) - java 源码中的策略模式

    标签(空格分隔): 设计模式 前言 Strategy(策略)设计模式是设计架构时候常用到的设计模式之一。我们开发中...

  • 前端设计模式

    JS设计模式一:工厂模式jS设计模式二:单例模式JS设计模式三:模块模式JS设计模式四:代理模式JS设计模式五:职...

  • 一文细读策略模式、策略模式与Spring的碰撞

    前言 策略模式是GoF23种设计模式中比较简单的了,也是常用的设计模式之一,今天我们就来看看策略模式。 实际案例 ...

  • 《iOS开发》--------常用的设计模式

    关于iOS开发中的设计模式,当下有集中最常用的设计模式:代理模式、观察者模式、MVC模式、单例模式、策略模式、工厂...

  • iOS开发中的几种设计模式

    目前常用的几种设计模式:代理模式、观察者模式、MVC模式、单例模式、策略模式、工厂模式、MVVM (一)代理 场景...

  • iOS开发中的几种设计模式

    目前常用的几种设计模式:代理模式、观察者模式、MVC模式、单例模式、策略模式、工厂模式、MVVM (一)代理 场景...

网友评论

    本文标题:js常用设计模式2-策略模式

    本文链接:https://www.haomeiwen.com/subject/rgnoaktx.html