【设计模式系列】之【策略模式】

前言:要提升代码水平,就绕不开设计模式。之前也有过一些了解,但并没有深入学习。最近准备系统的学习一下设计模式,提高设计,解耦的能力,发现了一本好书《JavaScript设计模式与开发实践》,所以边读边写,把常用的设计模式学习并记录在这里。

定义与介绍

单例模式的定义:定义一系列算法,把它们一个个封装起来,并且使它们可以互相替换。

策略模式是最亲民的设计模式了,即使之前没学过,在很多代码中我们都会不知不觉的使用简单的策略模式,但本篇简述的完整策略模式更加的面向对象

JavaScript中的策略模式

JavaScript中,函数也是对象,最直接的做法就是把策略直接定义为函数:

// 根据绩效和工资计算年终奖的例子:
// 根据绩效不同,有不同的算法,把这些算法封装成不同的策略
const strategies = {
	S: function(salary) {
		return salary * 4;
	},
	A: function(salary) {
		return salary * 3;
	},
	B: function(salary) {
		return salary * 2;
	}
}

const calculateBouns = function(level, salary) {
	return strategies[level](salary);
}

calculateBouns(S, 10000);

可以看到,上边的做法其实不需要学习,我们在日常编码中就很可能会自发的这样使用,仅仅针对这个例子而言,甚至可以更加简洁。当然这样做有好有坏,可以根据实际情况决定,如下:

const strategies = {
	S: 4,
	A: 3,
	B: 2,
}

const calculateBouns = function(level, salary) {
	return strategies[level] * salary;
}

calculateBouns(A, 20000);

策略模式的例子

我们有个很常见的表单校验需求,希望这些校验规则能够方便的替换和组合使用,来预防后期的需求变更。


// 表单结构
<html>
	<body>
		<form action='xxx' id='registerForm' method="POST">
			请输入用户名:<input type='text' name='userName' />
			请输入密码:<input type='text' name='password' />
			请输入手机号:<input type='text' name='mobile' />
		</form>
	</body>
<html>

// js
/******* 策略对象 ********/
const strategies = {
	isNotEmpty: function(val, errMsg) {
		if(val === '') {
			return errMsg
		}
	},
	minLength: function(val, minLen, errMsg) {
		if(val.length < minLen) {
			return errMsg
		}
	},
	isMobile: function(val, errMsg) {
		if(!/(^1[3|5|8][0-9]{9}$)/.test(val)) {
			return errMsg
		}
	}
}
/******* Validator 类 ********/
class Validator {
	constructor() {
		this.cache = [];
	}
	add(dom, rules) {
		rules.forEach(rule => {
			const strategyArr = rule.strategy.aplit(':');
			const errMsg = rule.errMsg;
			// catch中保存的是校验方法
			this.catch.push(function() {
				// 取出冒号左边的策略名称
				// 如 minLen: 6,为最小长度为6位
				const strategy = strategyArr.shift();
				// 把实际的输入值从左侧插入参数数组
				strategyArr.unshift(dom.value);
				// 把错误提示从右侧插入参数数组
				strategyArr.push(errMsg);
				// 取得对应的策略,使用apply在dom下执行,传入参数数组strategyArr
				return strategies[strategy].apply(dom, strategyArr);
			})
		})
	}
	start() {
		this.cacht.forEach(validatorFunc => {
			const errMsg = validatorFunc();
			if (errMsg) {
				return errMsg;
			}
		})
	}
}
/******* 调用代码 ********/
const registerForm = document.getElementById('registerForm');

const validataFunc = function() {
	const validator = new Validator();
	// 校验对象增加校验规则
	validator.add(registerForm.userName, [{
		strategy: 'isNotEmpty',
		errMsg: '用户名不能为空',
	}, {
		strategy: 'minLen: 10',
		errMsg: '用户名长度不能小于10位',
	}]);
	validator.add(registerForm.password, [{
		strategy: 'minLen: 6',
		errMsg: '用户名长度不能小于6位',
	}]);
	validator.add(registerForm.mobile, [{
		strategy: 'isMobile',
		errMsg: '手机号码格式不正确',
	}]);
	// 校验对象开始校验
	const errMsg = validator.start();
	return errMsg;
}

registerForm.onsubmit = function() {
	const errMsg = validataFunc();
	if(errMsg) {
		alert(errMsg)return
	}
	// do submit
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章