當我們的****現了一連串的if…else…或者是switch…case…語句時,我們的**體就會很長很臃腫,閱讀性大大下降,此時可採用策略模式進行重構。
策略模式利用的是物件導向語言的三個特性,尤其是繼承和多型。首先讓多個類繼承同乙個抽象的父類或者是實現乙個介面,在抽象類或者介面中宣告我們要實現的抽象方法,在子類或者實現類中寫出不同的方法實現。根據多型性,建立乙個父類型別的引用,讓其指向子類的物件,讓根據物件的不同,執行各個同名但不同體的方法。
影片類,具有標題,**碼(對應的是影片的型別):
public
class
movie
public
intgetpricecode()
public
void
setpricecode
(int pricecode)
public string gettitle()
}
租賃單類,包含一部電影和租賃的日期,同時還包含乙個計算租賃金的方法:
public
class
rental
public movie getmovie()
public
intgetdayrented()
public
double
getamount()
break
;case movie.new_release:
thisamount +=
this
.getdayrented()
*3;break
;case movie.childrens:
thisamount +=
1.5;if(
this
.getdayrented()
>3)
break;}
return thisamount;
}}
顧客類,包含姓名、租賃的影片、總的租金以及積分點,和乙個列印所有租賃資訊的方法printstatement
:
public
class
customer
public
void
addrental
(rental arg)
public string getname()
public
void
printheader()
public
void
printbody()
body +=
"\t"
+ each.
getmovie()
.gettitle()
+"\t"
+ each.
getamount()
+"\n"
; totalamount += each.
getamount()
;}system.out.
print
(body);}
public
void
printtail()
public
void
printstatement()
}
主類,用於執行和測試:
public
class
main
}
執行結果:
rental record for lily
鐵達尼號 3.5
amount owed is 3.5
you earned 1 frequent renter points
**其實不難理解(因為我覺得方法命名得還不錯…),根據使用者租賃的影片列印出使用者消費的票據,每部影片的租金根據電影的標籤和租賃時長計算,還可以累積積分點。
一眼看過去其實還是有幾個比較明顯的bad code smell,我們暫且先選擇性忽視它們…
rental類的getamount()方法屬於典型的長方法,又臭又長,大部分的原因是因為這個switch語句:
switch
(movie.
getpricecode()
)break
;case movie.new_release:
thisamount +=
this
.getdayrented()
*3;break
;case movie.childrens:
thisamount +=
1.5;if(
this
.getdayrented()
>3)
break
;}
接下來我們嘗試消除這段長**!!!
根據策略模式的思想,我們可以讓三個不同的類去繼承rental
類,在rental
類中新增乙個抽象方法,讓各個子類去給出不同的實現,這樣就可以取代不同的case。
abstract
public
class
rental
public movie getmovie()
public
intgetdayrented()
public
double
getamount()
abstract
public
double
countthisamount
(double thisamount)
;}
之前的判斷邏輯,全都被放到子類的繼承的抽象方法去實現:
public
class
newreleaserental
extends
rental
@override
public
double
countthisamount
(double thisamount)
}
public
class
regularrental
extends
rental
@override
public
double
countthisamount
(double thisamount)
return thisamount;
}}
public
class
childrenrental
extends
rental
@override
public
double
countthisamount
(double thisamount)
return thisamount;
}}
而原來的長方法,變得非常簡潔,大大增強了可讀性。
public
double
getamount()
策略模式正如其名字一樣,提供不同的策略,使用者只需要決定用哪個演算法,演算法內部被系統封裝。因此,策略模式多用在演算法決策系統中,對不同的輸入做不同處理:
策略模式在重構**中幫助很大,往往能消除長方法,大大提高**的可讀性。同時,經過策略模式重構後的**更易於擴充套件,一旦有新的條件出現,直接構建乙個新的策略就可以,不會影響其他**。
策略模式、模板模式、提取方法等都可以去重構**,好處在於,更易於後期的維護和繼續開發,利於**重用,**更具有可讀性。但是重構也會帶來一些問題,頻繁的函式呼叫會更耗費記憶體,過度地重構浪費開發時間,說不定還會減少可讀性。何解呢?業務需求必定是其一(emmmmmm),還是見仁見智吧,每個人都有自己的理解和行為習慣,只要你覺得ok,你的partners也ok,就ok(o)/~
小唐說設計模式 原型模式
原型模式 prototype pattern 是五種建立型模式的其中一種,用原型例項指定建立物件的種類作為原型,並且通過拷貝原型來建立新的物件。新建乙個物件有時候會很麻煩,可能涉及大量的變數初始化,函式 塊的執行,不僅浪費資源,還會涉及資料準備 訪問許可權等操作。原型模式至少涉及兩個角色 publi...
設計模式 策略設計模式
策略設計模式其實就是多型的使用,父類引用指向子類物件。策略模式的最大特點是使得演算法可以在不影響客戶端的情況下發生變化,從而改變不同的功能。策略模式的缺點其實也很明顯,在於策略模式把每一種具體的策略都封裝成乙個實現類,如果策略有很多的話,很顯然是實現類就會導致過多,顯得臃腫。案列 author de...
設計模式 策略模式
策略模式是一種定義一系列演算法的方法,從概念上來看,所有這些方法完成的都是相同的工作,只是實現不同,他們可以用相同的方式呼叫所有的演算法,減少了演算法類和使用演算法類之間的耦合.優點 策略模式的strategy類層次為context定義了一系列可供重用的演算法和行為,繼承有助於吸取這些演算法中的公共...