A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

策略模式指定义一系列算法,将它们一个个封装起来。将不变的部分与变化的部分隔开是每个设计模式的主题,策略模式同样如此,

策略模式的基础组成: 一个基于策略模式的程序至少要由两部分组成。第一个部分是一组策略类,策略类封装了具体的算法,并负责具体的计算过程。第二个部分是环境类Context,Context接收。

客户的请求,随后把请求委托给某一个策略类(发送消息给某个策略对象),要做到这点,说明Context中要维持对某个策略对象的引用。

简易表单校验示例DEMO:

<!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>
    <style>
        .error {
            color: #ff0000;
            font-size: 12px;
        }

    </style>
</head>
<body>
    <form action="http://www.x111xx.com/register" method="post" id="registerForm">
        <label>
            <input type="text" name="username" >
        </label>
        <label>
            <input type="password" name="password" >
        </label>
        <label>
            <input type="text" name="phoneNumber">
        </label>
        <button>提交</button>
    </form>
</body>
<script>

    //为元素同时设置多个属性方法
    var setAttributes = function(el, attrs){
        for(var key in attrs){
            el.setAttribute(key, attrs[key])
        }
    }

    //策略类
    var strategiesObj = {
        isNonEmpty: function(name, value, errorMsg){
            if(value === ''){
                var errObj = {errName: name, errValue: value, errMsg: errorMsg}
                return errObj
            }
        },
        minLength: function(name, value, length, errorMsg){
            if(value.length < length){
                var errObj = {errName: name, errValue: value, errLength: length, errMsg: errorMsg}
                return errObj
            }
        },
        isMobile: function(name, value, errorMsg){
            if(!/^1[3|4|5|7|8][0-9]{9}$/.test(value)){
                var errObj = {errName: name, errValue: value, errMsg: errorMsg}
                return errObj
            }
        }
    }

    //Context类
    var Validator = function(){
        this.cache = [];     //保存校验规则
        this.errArr = [];
    }

    Validator.prototype.add = function(name, dom, rules){
        var self = this;
        for(var i=0, rule; rule=rules[i++];){
            (function(rule){
                var strategyAry = rule.strategy.split(':');   //把strategy和rule分隔开
                self.cache.push(function(){     //把校验的步骤用空函数包裹起来,并且放入cache中,
                    var strategy = strategyAry.shift(strategyAry);   //用户选择的strategy   shift()方法是删除数组第一个元素,并返回第一个元素的值
                    strategyAry.unshift(name)
                    strategyAry.splice(1, 0, dom.value)   //把input的value添加进参数列表      unshift()方法是向数组的头部添加元素,并返回新数组的长度
                    strategyAry.push(rule.errorMsg)      //把errorMsg添加进参数列表
                    return strategiesObj[strategy].apply(null, strategyAry)
                })
            })(rule)
        }
    }

    Validator.prototype.start = function(){
        var msgArr = [];
        var msgObj = {};
        for(var i=0; this.cache; i++){    //此处的this.cache函数是在this.cache数组中保存的校验规则函数
            var resultArgs = this.cache();   //开始校验,并取得校验后返回信息
            if(resultArgs){    //如果有确切的返回值,说明校验没有通过
                msgArr.push({    //将策略类具体方法的返回值组合成数组对象,包含错误表单的索引、name、value、错误信息及其他自定义配置信息如长度
                    errIndex:i,
                    errName: resultArgs.errName,
                    errValue: resultArgs.errValue,
                    errMsg: resultArgs.errMsg,
                    errLength: resultArgs.errLength?resultArgs.errLength:''
                })
            }
        }
        this.errArr = msgArr;
        return msgArr
    }

    Validator.prototype.errShow = (function(){
        var singleErr = null;

        return function(){
            console.log(singleErr);
            if(!singleErr){
                for(var i=0, l=this.errArr.length; i<l; i++){
                    var label = document.createElement('label')
                    label.innerHTML = this.errArr.errMsg
                    setAttributes(label, {
                        'for': this.errArr.errName,
                        'id': this.errArr.errName + '-error',
                        'class': 'error'
                    })
                    //原生js插入兄弟节点是方法是获取父节点然后通过appendChild或者insertBefore方法插入
                    document.getElementsByName(this.errArr.errName)[0].parentNode.append(label)
                }
            }
            return singleErr = label;
        }
    })()

    //实例化Validator类
    var ValidatorFunc = function(){
        var validator = new Validator();        //创建一个validator对象

        //添加一些校验规则
        validator.add('username', registerForm.username, [{strategy: 'isNonEmpty', errorMsg: '用户名不能为空'}])
        validator.add('password', registerForm.password, [{strategy: 'minLength:6', errorMsg: '密码长度不能少于6位'}])
        validator.add('phoneNumber', registerForm.phoneNumber, [{strategy: 'isMobile', errorMsg: '手机号码格式不正确'}, {strategy: 'minLength:11', errorMsg: '手机号长度不能少于11位'}])

        var errorMsgArr = validator.start();   //获得校验结果
        validator.errShow()
        return errorMsgArr;    //返回校验结果
    }

    var registerForm = document.getElementById('registerForm')
    registerForm.onsubmit = function(){
        var errorMsgArr = ValidatorFunc(); //如果errorMsg有确切的返回值,说明未通过校验
        if(errorMsgArr){
            console.log(errorMsgArr);
            return false    //阻止表单提交
        }
    }

</script>
</html>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
这个DEMO还是存在bug的,比如重复点击提交按钮时会出现多次错误提示,这个应该可以通过将实例方法errShow改为类方法加闭包加单例模式来解决。另外在具体调用配置上还有很多可以优化的地方。

通过上面DEMO学习,可以体会到策略模式的优越性,比如可以用在多重条件选择语句上,将条件分支算法封装到策略类中,使得它们易于切换、易于理解,还容易扩展。
---------------------
【转载,仅作分享,侵删】
作者: 一期一会
原文:https://blog.csdn.net/qq_34832846/article/details/85988071


1 个回复

倒序浏览
奈斯
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马