目錄
前言
最近因爲業務臨時調整,被調派至另外一個子公司做一個使用Vue2的項目。在支撐任務還剩兩天臨別時,決定重構自己的業務邏輯代碼,留下自己好的印象給其他人(或許只是在挖坑)。因此,決定優雅地編寫設計模式。
正文
在Vue2的項目中,存在大量的流程化的業務功能,申請業務、業務流轉等等,一環扣一環,都是單節點流程。因此決定使用責任鏈設計模式。
責任鏈模式
顧名思義,責任鏈模式(Chain of Responsibility Pattern)爲請求創建了一個接收者對象的鏈。這種模式給予請求的類型,對請求的發送者和接收者進行解耦。這種類型的設計模式屬於行爲型模式。
在這種模式中,通常每個接收者都包含對另一個接收者的引用。如果一個對象不能處理該請求,那麼它會把相同的請求傳給下一個接收者,依此類推。
Vue中示例
在Vue的工程中,我們需要在責任鏈對象方法中劫持Vue內部的this對象,劫持this對象的方法有很多種,這裏提供一種簡單的方式去解決。
class Chain {
static NEXT_SUCCESSOR = 'nextSuccessor' // 保證this不被劫持
constructor (fn = function () {}, successor = null) {
this.handler = fn
this.successor = successor
}
// 設置下一個責任者
setSuccessor (successor) {
this.successor = successor
}
// 執行處理
handleRequest () {
const ret = this.handler(...arguments)
return ret === Chain.NEXT_SUCCESSOR && this.successor
? this.successor.handleRequest.apply(this.successor, arguments)
: ret
}
}
const apply = new Chain((data, other)=>{
if (data > 0) {
// @todo what you want
console.log('apply')
} else {
return Chain.NEXT_SUCCESSOR
}
})
const next = new Chain((data, other)=>{
if (data === 0) {
// @todo what you want
console.log('next')
} else {
return Chain.NEXT_SUCCESSOR
}
})
const complete = new Chain((data, other)=>{
if (data < 0) {
// @todo what you want
console.log('complete')
} else {
return Chain.NEXT_SUCCESSOR
}
})
// 關聯鏈式關係
apply.setSuccessor(next)
next.setSuccessor(complete)
apply.handleRequest(2, {})
// 結果是輸出 apply
上面的責任鏈其實取代在業務邏輯負責的流程業務代碼,就是取代嵌套的if ... else或者switch語句
if(data > 0){
console.log('apply')
} else if (data < 0){
console.log('next')
} else{
console.log('complete')
}
甚至可以替代更加複雜的內容
切面編程
在Vue的實際生產項目中,肯定有很多日誌記錄,性能統計,安全控制,事務處理,異常處理等代碼,如果要把代碼劃分出來,而不影響業務邏輯。從而讓業務邏輯更加獨立,更加乾淨。這個時候,可以使用切面編程。
JavaScript在實現切面編程的理念上是十分簡單的。因爲JavaScript是真正的面向對象的語言,哈哈
Vue中示例
// aop切面構造函數
const aopConstructor = function (o, b, a) {
return function _constructor () {
b.apply(this, arguments) //arguments是指向實際調用的方法時的參數列表
o.apply(this, arguments)
a.apply(this, arguments)
}
}
比如,我們需要對某個業務接口統計他的處理時間,那麼我們可以這麼處理
function before(data) {
// 輸出當前的時間戳
console.log('api調用前:' + new Date().getTime())
}
funciton after(data){
// 輸出當前的時間戳
console.log('api調用後:' + new Date().getTime())
}
function myApi(data) {
// @todo 處理業務接口的核心邏輯
}
const f = aopConstructor.call(this, myApi, before, after) // 若需要處理this就可以選擇劫持this
f.call(this, {}) // 在Vue中這裏需要劫持this對象
總結
在編寫複雜業務邏輯時,使用設計模式會讓業務邏輯更加清晰。也能讓代碼更加的優雅,讓人更加舒服,減少維護的時間。
而在Vue中使用設計模式,主要還是處理一下如何劫持Vue對象的this對象,僅此而已