相信有很多人在開發過程當中都遇到一大串的if/else判斷,代碼又臭又長,並且隨着需求的增長與產品的迭代,判斷條件可能愈來愈長,愈來愈難以維護,有沒有什麼好的方式去解決這種弊端呢?答案是確定的,策略模式是一種很好的解決辦法,能夠幫助咱們重構規範業務代碼,提升代碼的可讀性與可維護性。算法
首先,策略模式什麼?ui
策略模式就是定義一系列的算法,把他們各自封裝成策略類,算法被封裝在策略類內部的方法裏。在客戶對Context發起請求時,Context老是把請求委託給這些策略對象中間的某一個進行計算。this
簡單來講,就是將業務邏輯中公有的部分提取出來,封裝成一個環境類Context,具體的業務實現過程封裝在策略類strategies中,業務請求經過環境類去調用策略類中的實現過程,經過環境類給業務請求以響應消息,其中環境類充當一層代理,將類似的業務邏輯進行總結概括整理,提升代碼的可讀性與可維護性。本文以表單驗證爲例,來介紹策略模式在實際開發中的使用。spa
策略模式最起碼由兩部分組成:prototype
一、策略類代理
封裝某個策略的具體實現方法code
二、環境類Contextorm
接收客戶端業務處理請求,根據請求參數,調用策略類中具體的實現方法,策略類中必需要有處理方法;對象
以表單驗證爲例,其策略模式的實現過程以下:blog
function isFunction(fn) { return Object.prototype.toString.call(fn) === '[object Function]' } function isObject(obj) { return Object.prototype.toString.call(obj) === '[object Object]' } /** * 策略實現類 */ const validateStrategies = { checkPattern: { mobileReg: /^(((13[0-9]{1})|(14[0-9]{1})|(15[0-9]{1})|(16[0-9]{1})|(17[0-9]{1})|(18[0-9]{1})|(19[0-9]{1}))+\d{8})$/, numReg: /^[0-9]+(\.[0-9]{1,2})?$/ }, validateMobile(item) { let flag = true; if (item.data && !this.checkPattern.mobileReg.test(item.data)) { flag = false; } return flag; }, validateNumber(item) { let flag = true; if (!this.checkPattern.numReg.test(item.data)) { flag = false; } else if (item.point) { let pattern = new RegExp(`^[0-9]+(\.[0-9]{1,${item.point}})?$`); if (!pattern.test(item.data)) { flag = false; } } return flag; }, //校驗字段是否必填 validateRequired(item) { let flag = true; if (!item.data) { flag = false; } else { flag = true; } return flag; } }; class ValidateForm { constructor() { this.cache = []; } add(rules) { if (Array.isArray(rules)) { this.cache = [...this.cache, ...rules]; } else if (isObject(rules)) { this.cache = [...this.cache, rules]; } else { messagee.error(`參數類型應該爲Object或Array,可是卻傳入了${typeof rules}`, 2); } } remove(id) { let index = this.cache.findIndex(vv => vv.id && Object.is(vv.id, id)); this.cache.splice(index, 1); } start() { for (let i = 0, len = this.cache.length; i < len; i++) { let item = this.cache[i]; //傳入的驗證方法必須是一個function if (!isFunction(validateStrategies[item.validateFun])) { message.error('表單校驗參數格式錯誤', 2); return false; } else { let flag = validateStrategies[item.validateFun](item); if (!flag) { return flag; } } } return true; } } export default ValidateForm;
上述代碼,咱們聲明瞭一個ValidateForm類和一個validateStrategies策略對象,策略對象中封裝了一些表單驗證方法,在實例化Validate表單驗證類的時候,須要往表單驗證類中注入特定的表單校驗規則,而後調用下啓動方法,就能獲得表單驗證結果,以上代碼使用過程以下:
* 一、let validate = new ValidateForm(); * 二、加入驗證規則 validate.add(rules:Array<Object>) * 3、開始校驗 validate.start() * @param rules:Array<Object> { * validateFun: '', //校驗方法 * data: '',//校驗的數據 * maxSize: '', //最大值 * ponit: '' //小數點 * ... * }
其中validateFun對應的是策略類中具體的方法名,其他參數能夠根據業務需求酌情添加。饒了一大圈,這麼作的好處是什麼呢?
一、易維護擴展
如表單驗證,在添加驗證規則時,只須要加入一個具體的策略實現方法便可,不須要額外改動其餘業務代碼
二、可讀性較高
熟悉某個具體功能邏輯不須要看一些不相關的內容
三、代碼複用性較高
利用排列組合的方式,能夠提升代碼的複用性