面向过程:将项目分解成很多步骤,为每个步骤编写代码。可维护性差。
面向对象:将项目分解成一个一个方法,然后根据每个步骤的需要调用方法。可维护性好。
面向对象的 SOLID 原则
设计模式是一套经验,是对于某一类特定问题的简洁而优雅的解决方案
应用场景:当需要根据不同情景从多种算法中选择一种执行时
重点思想:将变与不变分离
具体实现:将 不变的 算法封装在 策略类 中, 策略类 只负责算法,传入参数传出参数; 变化的 是客户端的请求,放在 情景类 中, 情景类 负责接收客户端的请求并委托给 策略类
需求:对 A 类型会员提供 20% 的促销折扣,对 B 类型会员提供 10% 的促销折扣,对 C 类型会员没有折扣
首先我们定义会员折扣
- // 定义不同会员的折扣
- const discountA = 0.8,
- discountB = 0.9,
- discountC = 1;
最初的实现↓
- // 计算折扣价格函数
- function calculatePrice(type, totalPrice) {
- if(type === 'A') {
- return totalPrice*discountA;
- }
- if(type === 'B') {
- return totalPrice*discountB;
- }
- if(type === 'C') {
- return totalPrice*discountC;
- }
- }
- // 调用函数
- console.log(calculatePrice('A',100));
分析:算法是不变的,变的是会员类型和总价
运用策略模式↓
- // 定义策略对象
- const strategies = {
- A: function(totalPrice) {
- return totalPrice*discountA;
- },
- B: function(totalPrice) {
- return totalPrice*discountB;
- },
- C: function(totalPrice) {
- return totalPrice*discountC;
- },
- }
- // 定义情景类
- function calculatePrice(type, totalPrice) {
- return strategies[type](totalPrice);
- }
- // 调用函数计算折扣价
- console.log(calculatePrice('A',100));
策略对象还可以进一步抽象。
- // 定义策略对象
- const strategies = {
- A: discountA,
- B: discountB,
- C: discountC,
- }
- // 定义情景类
- function calculatePrice(type, totalPrice) {
- return strategies[type]*(totalPrice);
- }
- // 调用函数计算折扣价
- console.log(calculatePrice('A',100));
需求: 用户名 不可为空, 密码 不能小于 6 位, 手机号码 格式正确
- // 伪一组数据
- const registerForm = {
- userName: 'liuxiaocui',
- password: 'lxc123456',
- phone: '18628337983',
- }
最初的实现↓
- // 校验函数
- function validate(data) {
- if(data.userName === '') {
- console.log('用户名不能为空');
- return;
- }
- if (data.password.length < 6) {
- console.log('密码长度不能小于6位');
- return;
- }
- if (!/(^1[3|5|8][0-9]{9}$)/.test(data.phone)) {
- console.log('手机号码格式不正确');
- return;
- }
- return true;
- }
- // 提交表单函数
- function onSubmit(data) {
- if(validate(data)) {
- console.log('通过校验');
- // 别的操作blabla
- }
- }
- // 调用提交表单函数
- onSubmit(registerForm);
分析:校验算法是不变的,变的是数据和校验要求
运用策略模式↓
首先定义策略对象,注意每个函数的传参。所有参数应该外部传入。
- // 定义策略对象
- const 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;
- }
- }
- }
回顾下需求。我们希望能方便得对数据进行校验,也很可能一个数据需要多条校验规则。
先来看下校验函数是怎么写的。
- // 校验函数
- function validate(data) {
- const validator = new Validator();
- validator.add(data.userName, [{
- strategy: 'isNonEmpty',
- errorMsg: '用户名不能为空'
- },
- {
- strategy: 'minLength:10',
- errorMsg: '用户名长度不能小于10位'
- }]);
- validator.add(data.password, [{
- strategy: 'minLength:6',
- errorMsg: '密码长度不能小于6位'
- }]);
- validator.add(data.phone, [{
- strategy: 'isMobile',
- errorMsg: '手机号码格式不正确'
- }]);
- return validator.start();
- }
- // 提交表单函数
- function onSubmit(data) {
- const errorMsg = validate(data);
- if(errorMsg) {
- console.log(errorMsg);
- } else {
- console.log('通过校验');
- // 别的操作blabla
- }
- }
- // 调用函数
- onSubmit(registerForm);
下面是情景类。
- // 定义情景类
- var Validator = function() {
- // 存下需要进行的校验
- this.cache = [];
- }
- // 增加需要进行的校验
- Validator.prototype.add = function(data, rules) {
- rules.forEach( item => {
- // strategyAry的第一个元素为strategy名字,第二个值(如果有)为限制值
- const strategyAry = item.strategy.split(':');
- const errorMsg = item.errorMsg;
- this.cache.push(function() {
- const strategy = strategyAry.shift();
- // unshift() 方法可向数组的开头添加一个或更多元素,并返回新的长度。
- // 把要校验的数据放在数组第一位
- strategyAry.unshift(data);
- // 把错误信息放在数组最后一位
- strategyAry.push(errorMsg);
- // return strategies[strategy](...strategyAry);
- return strategies[strategy].apply(null,strategyAry);
- })
- })
- }
- // 开始校验
- Validator.prototype.start = function() {
- // 挨个运行this.cache中的校验函数
- for(let validatorFunc of this.cache) {
- const errorMsg = validatorFunc();
- if(errorMsg) {
- return errorMsg;
- }
- }
- }
策略模式优点:将不变的算法单独封装在 策略类 中,通过 情景类 来接收请求并委托给 策略类 ,代码结构清晰,使用方便
策略模式缺点:使用之前需要知道所有的策略类函数
来源: http://www.open-open.com/lib/view/open1490083753178.html