新聞中心
設(shè)計(jì)模式是眾多軟件開(kāi)發(fā)人員經(jīng)過(guò)長(zhǎng)時(shí)間的試錯(cuò)和應(yīng)用總結(jié)出來(lái)的,解決特定問(wèn)題的一系列方案?,F(xiàn)行的部分教材在介紹設(shè)計(jì)模式時(shí),有些會(huì)因?yàn)榘咐撾x實(shí)際應(yīng)用場(chǎng)景而令人費(fèi)解,有些又會(huì)因?yàn)閳?chǎng)景簡(jiǎn)單而顯得有些小題大做。

站在用戶的角度思考問(wèn)題,與客戶深入溝通,找到瑞金網(wǎng)站設(shè)計(jì)與瑞金網(wǎng)站推廣的解決方案,憑借多年的經(jīng)驗(yàn),讓設(shè)計(jì)與互聯(lián)網(wǎng)技術(shù)結(jié)合,創(chuàng)造個(gè)性化、用戶體驗(yàn)好的作品,建站類(lèi)型包括:成都網(wǎng)站設(shè)計(jì)、成都網(wǎng)站建設(shè)、企業(yè)官網(wǎng)、英文網(wǎng)站、手機(jī)端網(wǎng)站、網(wǎng)站推廣、空間域名、虛擬空間、企業(yè)郵箱。業(yè)務(wù)覆蓋瑞金地區(qū)。
本文會(huì)根據(jù)在美團(tuán)金融服務(wù)平臺(tái)設(shè)計(jì)開(kāi)發(fā)時(shí)的經(jīng)驗(yàn),結(jié)合實(shí)際的案例,并采用“師生對(duì)話”這種相對(duì)詼諧的形式去講解幾類(lèi)常用設(shè)計(jì)模式的應(yīng)用。希望能對(duì)想提升系統(tǒng)設(shè)計(jì)能力的同學(xué)有所幫助或啟發(fā)。
引言
話說(shuō)這是在程序員世界里一對(duì)師徒的對(duì)話:“老師,我最近在寫(xiě)代碼時(shí)總感覺(jué)自己的代碼很不優(yōu)雅,有什么辦法能優(yōu)化嗎?”“嗯,可以考慮通過(guò)教材系統(tǒng)學(xué)習(xí),從注釋、命名、方法和異常等多方面實(shí)現(xiàn)整潔代碼?!薄叭欢蚁胝f(shuō)的是,我的代碼是符合各種編碼規(guī)范的,但是從實(shí)現(xiàn)上卻總是感覺(jué)不夠簡(jiǎn)潔,而且總是需要反復(fù)修改!”學(xué)生小明嘆氣道。老師看了看小明的代碼說(shuō):“我明白了,這是系統(tǒng)設(shè)計(jì)上的缺陷。總結(jié)就是抽象不夠、可讀性低、不夠健壯?!薄皩?duì)對(duì)對(duì),那怎么能迅速提高代碼的可讀性、健壯性、擴(kuò)展性呢?”小明急不可耐地問(wèn)道。老師敲了敲小明的頭:“不要太浮躁,沒(méi)有什么方法能讓你立刻成為系統(tǒng)設(shè)計(jì)專(zhuān)家。但是對(duì)于你的問(wèn)題,我想設(shè)計(jì)模式可以幫到你?!薄霸O(shè)計(jì)模式?”小明不解?!笆堑??!崩蠋燑c(diǎn)了點(diǎn)頭,“世上本沒(méi)有路,走的人多了,便變成了路。在程序員的世界中,本沒(méi)有設(shè)計(jì)模式,寫(xiě)代碼是人多了,他們便總結(jié)出了一套能提高開(kāi)發(fā)和維護(hù)效率的套路,這就是設(shè)計(jì)模式。設(shè)計(jì)模式不是什么教條或者范式,它可以說(shuō)是一種在特定場(chǎng)景下普適且可復(fù)用的解決方案,是一種可以用于提高代碼可讀性、可擴(kuò)展性、可維護(hù)性和可測(cè)性的最佳實(shí)踐?!薄芭杜叮叶?,那我應(yīng)該如何去學(xué)習(xí)呢?”“不急,接下來(lái)我來(lái)帶你慢慢了解設(shè)計(jì)模式?!?/p>
獎(jiǎng)勵(lì)的發(fā)放策略
第一天,老師問(wèn)小明:“你知道活動(dòng)營(yíng)銷(xiāo)嗎?”“這我知道,活動(dòng)營(yíng)銷(xiāo)是指企業(yè)通過(guò)參與社會(huì)關(guān)注度高的已有活動(dòng),或整合有效的資源自主策劃大型活動(dòng),從而迅速提高企業(yè)及其品牌的知名度、美譽(yù)度和影響力,常見(jiàn)的比如有抽獎(jiǎng)、紅包等。”老師點(diǎn)點(diǎn)頭:“是的。我們假設(shè)現(xiàn)在就要做一個(gè)營(yíng)銷(xiāo),需要用戶參與一個(gè)活動(dòng),然后完成一系列的任務(wù),最后可以得到一些獎(jiǎng)勵(lì)作為回報(bào)?;顒?dòng)的獎(jiǎng)勵(lì)包含美團(tuán)外賣(mài)、酒旅和美食等多種品類(lèi)券,現(xiàn)在需要你幫忙設(shè)計(jì)一套獎(jiǎng)勵(lì)發(fā)放方案?!币?yàn)橹坝羞^(guò)類(lèi)似的開(kāi)發(fā)經(jīng)驗(yàn),拿到需求的小明二話不說(shuō)開(kāi)始了編寫(xiě)起了代碼:
// 獎(jiǎng)勵(lì)服務(wù)
class RewardService {
// 外部服務(wù)
private WaimaiService waimaiService;
private HotelService hotelService;
private FoodService foodService;
// 使用對(duì)入?yún)⒌臈l件判斷進(jìn)行發(fā)獎(jiǎng)
public void issueReward(String rewardType, Object ... params) {
if ("Waimai".equals(rewardType)) {
WaimaiRequest request = new WaimaiRequest();
// 構(gòu)建入?yún)?br> request.setWaimaiReq(params);
waimaiService.issueWaimai(request);
} else if ("Hotel".equals(rewardType)) {
HotelRequest request = new HotelRequest();
request.addHotelReq(params);
hotelService.sendPrize(request);
} else if ("Food".equals(rewardType)) {
FoodRequest request = new FoodRequest(params);
foodService.getCoupon(request);
} else {
throw new IllegalArgumentException("rewardType error!");
}
}
}
// 獎(jiǎng)勵(lì)服務(wù)
class RewardService {
// 外部服務(wù)
private WaimaiService waimaiService;
private HotelService hotelService;
private FoodService foodService;
// 使用對(duì)入?yún)⒌臈l件判斷進(jìn)行發(fā)獎(jiǎng)
public void issueReward(String rewardType, Object ... params) {
if ("Waimai".equals(rewardType)) {
WaimaiRequest request = new WaimaiRequest();
// 構(gòu)建入?yún)?br> request.setWaimaiReq(params);
waimaiService.issueWaimai(request);
} else if ("Hotel".equals(rewardType)) {
HotelRequest request = new HotelRequest();
request.addHotelReq(params);
hotelService.sendPrize(request);
} else if ("Food".equals(rewardType)) {
FoodRequest request = new FoodRequest(params);
foodService.getCoupon(request);
} else {
throw new IllegalArgumentException("rewardType error!");
}
}
}
小明很快寫(xiě)好了Demo,然后發(fā)給老師看?!凹偃缥覀兗磳⒔尤胄碌拇蜍?chē)券,這是否意味著你必須要修改這部分代碼?”老師問(wèn)道。小明愣了一愣,沒(méi)等反應(yīng)過(guò)來(lái)老師又問(wèn):”假如后面美團(tuán)外賣(mài)的發(fā)券接口發(fā)生了改變或者替換,這段邏輯是否必須要同步進(jìn)行修改?”小明陷入了思考之中,一時(shí)間沒(méi)法回答。經(jīng)驗(yàn)豐富的老師一針見(jiàn)血地指出了這段設(shè)計(jì)的問(wèn)題:“你這段代碼有兩個(gè)主要問(wèn)題,一是不符合開(kāi)閉原則,可以預(yù)見(jiàn),如果后續(xù)新增品類(lèi)券的話,需要直接修改主干代碼,而我們提倡代碼應(yīng)該是對(duì)修改封閉的;二是不符合迪米特法則,發(fā)獎(jiǎng)邏輯和各個(gè)下游接口高度耦合,這導(dǎo)致接口的改變將直接影響到代碼的組織,使得代碼的可維護(hù)性降低。”小明恍然大悟:“那我將各個(gè)同下游接口交互的功能抽象成單獨(dú)的服務(wù),封裝其參數(shù)組裝及異常處理,使得發(fā)獎(jiǎng)主邏輯與其解耦,是否就能更具備擴(kuò)展性和可維護(hù)性?”“這是個(gè)不錯(cuò)的思路。之前跟你介紹過(guò)設(shè)計(jì)模式,這個(gè)案例就可以使用策略模式和適配器模式來(lái)優(yōu)化。”小明借此機(jī)會(huì)學(xué)習(xí)了這兩個(gè)設(shè)計(jì)模式。首先是策略模式:
策略模式定義了一系列的算法,并將每一個(gè)算法封裝起來(lái),使它們可以相互替換。策略模式通常包含以下角色:
- 抽象策略(Strategy)類(lèi):定義了一個(gè)公共接口,各種不同的算法以不同的方式實(shí)現(xiàn)這個(gè)接口,環(huán)境角色使用這個(gè)接口調(diào)用不同的算法,一般使用接口或抽象類(lèi)實(shí)現(xiàn)。
- 具體策略(Concrete Strategy)類(lèi):實(shí)現(xiàn)了抽象策略定義的接口,提供具體的算法實(shí)現(xiàn)。
- 環(huán)境(Context)類(lèi):持有一個(gè)策略類(lèi)的引用,最終給客戶端調(diào)用。
然后是適配器模式:
適配器模式:將一個(gè)類(lèi)的接口轉(zhuǎn)換成客戶希望的另外一個(gè)接口,使得原本由于接口不兼容而不能一起工作的那些類(lèi)能一起工作。適配器模式包含以下主要角色:
- 目標(biāo)(Target)接口:當(dāng)前系統(tǒng)業(yè)務(wù)所期待的接口,它可以是抽象類(lèi)或接口。
- 適配者(Adaptee)類(lèi):它是被訪問(wèn)和適配的現(xiàn)存組件庫(kù)中的組件接口。
- 適配器(Adapter)類(lèi):它是一個(gè)轉(zhuǎn)換器,通過(guò)繼承或引用適配者的對(duì)象,把適配者接口轉(zhuǎn)換成目標(biāo)接口,讓客戶按目標(biāo)接口的格式訪問(wèn)適配者。
結(jié)合優(yōu)化思路,小明首先設(shè)計(jì)出了策略接口,并通過(guò)適配器的思想將各個(gè)下游接口類(lèi)適配成策略類(lèi):
// 策略接口
interface Strategy {
void issue(Object ... params);
}
// 外賣(mài)策略
class Waimai implements Strategy {
private WaimaiService waimaiService;
@Override
public void issue(Object... params) {
WaimaiRequest request = new WaimaiRequest();
// 構(gòu)建入?yún)?br> request.setWaimaiReq(params);
waimaiService.issueWaimai(request);
}
}
// 酒旅策略
class Hotel implements Strategy {
private HotelService hotelService;
@Override
public void issue(Object... params) {
HotelRequest request = new HotelRequest();
request.addHotelReq(params);
hotelService.sendPrize(request);
}
}
// 美食策略
class Food implements Strategy {
private FoodService foodService;
@Override
public void issue(Object... params) {
FoodRequest request = new FoodRequest(params);
foodService.payCoupon(request);
}
}
// 策略接口
interface Strategy {
void issue(Object ... params);
}
// 外賣(mài)策略
class Waimai implements Strategy {
private WaimaiService waimaiService;
@Override
public void issue(Object... params) {
WaimaiRequest request = new WaimaiRequest();
// 構(gòu)建入?yún)?br> request.setWaimaiReq(params);
waimaiService.issueWaimai(request);
}
}
// 酒旅策略
class Hotel implements Strategy {
private HotelService hotelService;
@Override
public void issue(Object... params) {
HotelRequest request = new HotelRequest();
request.addHotelReq(params);
hotelService.sendPrize(request);
}
}
// 美食策略
class Food implements Strategy {
private FoodService foodService;
@Override
public void issue(Object... params) {
FoodRequest request = new FoodRequest(params);
foodService.payCoupon(request);
}
}
然后,小明創(chuàng)建策略模式的環(huán)境類(lèi),并供獎(jiǎng)勵(lì)服務(wù)調(diào)用:
// 使用分支判斷獲取的策略上下文
class StrategyContext {
public static Strategy getStrategy(String rewardType) {
switch (rewardType) {
case "Waimai":
return new Waimai();
case "Hotel":
return new Hotel();
case "Food":
return new Food();
default:
throw new IllegalArgumentException("rewardType error!");
}
}
}
// 優(yōu)化后的策略服務(wù)
class RewardService {
public void issueReward(String rewardType, Object ... params) {
Strategy strategy = StrategyContext.getStrategy(rewardType);
strategy.issue(params);
}
}
// 使用分支判斷獲取的策略上下文
class StrategyContext {
public static Strategy getStrategy(String rewardType) {
switch (rewardType) {
case "Waimai":
return new Waimai();
case "Hotel":
return new Hotel();
case "Food":
return new Food();
default:
throw new IllegalArgumentException("rewardType error!");
}
}
}
// 優(yōu)化后的策略服務(wù)
class RewardService {
public void issueReward(String rewardType, Object ... params) {
Strategy strategy = StrategyContext.getStrategy(rewardType);
strategy.issue(params);
}
}
小明的代碼經(jīng)過(guò)優(yōu)化后,雖然結(jié)構(gòu)和設(shè)計(jì)上比之前要復(fù)雜不少,但考慮到健壯性和拓展性,還是非常值得的?!翱?,我這次優(yōu)化后的版本是不是很完美?”小明洋洋得意地說(shuō)?!榜詈隙却_實(shí)降低了,但還能做的更好?!薄霸趺醋觯俊毙∶饔悬c(diǎn)疑惑?!拔覇?wèn)你,策略類(lèi)是有狀態(tài)的模型嗎?如果不是是否可以考慮做成單例的?”“的確如此?!毙∶魉坪趺靼琢??!斑€有一點(diǎn),環(huán)境類(lèi)的獲取策略方法職責(zé)很明確,但是你依然沒(méi)有做到完全對(duì)修改封閉。”經(jīng)過(guò)老師的點(diǎn)撥,小明很快也領(lǐng)悟到了要點(diǎn):“那我可以將策略類(lèi)單例化以減少開(kāi)銷(xiāo),并實(shí)現(xiàn)自注冊(cè)的功能徹底解決分支判斷。”小明列出單例模式的要點(diǎn):
單例模式設(shè)計(jì)模式屬于創(chuàng)建型模式,它提供了一種創(chuàng)建對(duì)象的最佳方式。這種模式涉及到一個(gè)單一的類(lèi),該類(lèi)負(fù)責(zé)創(chuàng)建自己的對(duì)象,同時(shí)確保只有單個(gè)對(duì)象被創(chuàng)建。這個(gè)類(lèi)提供了一種訪問(wèn)其唯一的對(duì)象的方式,可以直接訪問(wèn),不需要實(shí)例化該類(lèi)的對(duì)象。
最終,小明在策略環(huán)境類(lèi)中使用一個(gè)注冊(cè)表來(lái)記錄各個(gè)策略類(lèi)的注冊(cè)信息,并提供接口供策略類(lèi)調(diào)用進(jìn)行注冊(cè)。同時(shí)使用餓漢式單例模式去優(yōu)化策略類(lèi)的設(shè)計(jì):
// 策略上下文,用于管理策略的注冊(cè)和獲取
class StrategyContext {
private static final MapregisterMap = new HashMap<>();
// 注冊(cè)策略
public static void registerStrategy(String rewardType, Strategy strategy) {
registerMap.putIfAbsent(rewardType, strategy);
}
// 獲取策略
public static Strategy getStrategy(String rewardType) {
return registerMap.get(rewardType);
}
}
// 抽象策略類(lèi)
abstract class AbstractStrategy implements Strategy {
// 類(lèi)注冊(cè)方法
public void register() {
StrategyContext.registerStrategy(getClass().getSimpleName(), this);
}
}
// 單例外賣(mài)策略
class Waimai extends AbstractStrategy implements Strategy {
private static final Waimai instance = new Waimai();
private WaimaiService waimaiService;
private Waimai() {
register();
}
public static Waimai getInstance() {
return instance;
}
@Override
public void issue(Object... params) {
WaimaiRequest request = new WaimaiRequest();
// 構(gòu)建入?yún)?br> request.setWaimaiReq(params);
waimaiService.issueWaimai(request);
}
}
// 單例酒旅策略
class Hotel extends AbstractStrategy implements Strategy {
private static final Hotel instance = new Hotel();
private HotelService hotelService;
private Hotel() {
register();
}
public static Hotel getInstance() {
return instance;
}
@Override
public void issue(Object... params) {
HotelRequest request = new HotelRequest();
request.addHotelReq(params);
hotelService.sendPrize(request);
}
}
// 單例美食策略
class Food extends AbstractStrategy implements Strategy {
private static final Food instance = new Food();
private FoodService foodService;
private Food() {
register();
}
public static Food getInstance() {
return instance;
}
@Override
public void issue(Object... params) {
FoodRequest request = new FoodRequest(params);
foodService.payCoupon(request);
}
}
// 策略上下文,用于管理策略的注冊(cè)和獲取
class StrategyContext {
private static final MapregisterMap = new HashMap<>();
// 注冊(cè)策略
public static void registerStrategy(String rewardType, Strategy strategy) {
registerMap.putIfAbsent(rewardType, strategy);
}
// 獲取策略
public static Strategy getStrategy(String rewardType) {
return registerMap.get(rewardType);
}
}
// 抽象策略類(lèi)
abstract class AbstractStrategy implements Strategy {
// 類(lèi)注冊(cè)方法
public void register() {
StrategyContext.registerStrategy(getClass().getSimpleName(), this);
}
}
// 單例外賣(mài)策略
class Waimai extends AbstractStrategy implements Strategy {
private static final Waimai instance = new Waimai();
private WaimaiService waimaiService;
private Waimai() {
register();
}
public static Waimai getInstance() {
return instance;
}
@Override
public void issue(Object... params) {
WaimaiRequest request = new WaimaiRequest();
// 構(gòu)建入?yún)?br> request.setWaimaiReq(params);
waimaiService.issueWaimai(request);
}
}
// 單例酒旅策略
class Hotel extends AbstractStrategy implements Strategy {
private static final Hotel instance = new Hotel();
private HotelService hotelService;
private Hotel() {
register();
}
public static Hotel getInstance() {
return instance;
}
@Override
public void issue(Object... params) {
HotelRequest request = new HotelRequest();
request.addHotelReq(params);
hotelService.sendPrize(request);
}
}
// 單例美食策略
class Food extends AbstractStrategy implements Strategy {
private static final Food instance = new Food();
private FoodService foodService;
private Food() {
register();
}
public static Food getInstance() {
return instance;
}
@Override
public void issue(Object... params) {
FoodRequest request = new FoodRequest(params);
foodService.payCoupon(request);
}
}
最終,小明設(shè)計(jì)完成的結(jié)構(gòu)類(lèi)圖如下:
獎(jiǎng)勵(lì)發(fā)放策略_類(lèi)圖
如果使用了Spring框架,還可以利用Spring的Bean機(jī)制來(lái)代替上述的部分設(shè)計(jì),直接使用@Component和@PostConstruct注解即可完成單例的創(chuàng)建和注冊(cè),代碼會(huì)更加簡(jiǎn)潔。至此,經(jīng)過(guò)了多次討論、反思和優(yōu)化,小明終于得到了一套低耦合高內(nèi)聚,同時(shí)符合開(kāi)閉原則的設(shè)計(jì)。“老師,我開(kāi)始學(xué)會(huì)利用設(shè)計(jì)模式去解決已發(fā)現(xiàn)的問(wèn)題。這次我做得怎么樣?”“合格。但是,依然要戒驕戒躁。”
任務(wù)模型的設(shè)計(jì)
“之前讓你設(shè)計(jì)獎(jiǎng)勵(lì)發(fā)放策略你還記得嗎?”老師忽然問(wèn)道?!爱?dāng)然記得。一個(gè)好的設(shè)計(jì)模式,能讓工作事半功倍?!毙∶鞔鸬??!班?,那會(huì)提到了活動(dòng)營(yíng)銷(xiāo)的組成部分,除了獎(jiǎng)勵(lì)之外,貌似還有任務(wù)吧?!毙∶鼽c(diǎn)了點(diǎn)頭,老師接著說(shuō):“現(xiàn)在,我想讓你去完成任務(wù)模型的設(shè)計(jì)。你需要重點(diǎn)關(guān)注狀態(tài)的流轉(zhuǎn)變更,以及狀態(tài)變更后的消息通知?!毙∶餍廊唤酉铝死蠋熃o的難題。他首先定義了一套任務(wù)狀態(tài)的枚舉和行為的枚舉:
// 任務(wù)狀態(tài)枚舉
@AllArgsConstructor
@Getter
enum TaskState {
INIT("初始化"),
ONGOING( "進(jìn)行中"),
PAUSED("暫停中"),
FINISHED("已完成"),
EXPIRED("已過(guò)期")
;
private final String message;
}
// 行為枚舉
@AllArgsConstructor
@Getter
enum ActionType {
START(1, "開(kāi)始"),
STOP(2, "暫停"),
ACHIEVE(3, "完成"),
EXPIRE(4, "過(guò)期")
;
private final int code;
private final String message;
}
// 任務(wù)狀態(tài)枚舉
@AllArgsConstructor
@Getter
enum TaskState {
INIT("初始化"),
ONGOING( "進(jìn)行中"),
PAUSED("暫停中"),
FINISHED("已完成"),
EXPIRED("已過(guò)期")
;
private final String message;
}
// 行為枚舉
@AllArgsConstructor
@Getter
enum ActionType {
START(1, "開(kāi)始"),
STOP(2, "暫停"),
ACHIEVE(3, "完成"),
EXPIRE(4, "過(guò)期")
;
private final int code;
private final String message;
}
然后,小明對(duì)開(kāi)始編寫(xiě)狀態(tài)變更功能:
class Task {
private Long taskId;
// 任務(wù)的默認(rèn)狀態(tài)為初始化
private TaskState state = TaskState.INIT;
// 活動(dòng)服務(wù)
private ActivityService activityService;
// 任務(wù)管理器
private TaskManager taskManager;
// 使用條件分支進(jìn)行任務(wù)更新
public void updateState(ActionType actionType) {
if (state == TaskState.INIT) {
if (actionType == ActionType.START) {
state = TaskState.ONGOING;
}
} else if (state == TaskState.ONGOING) {
if (actionType == ActionType.ACHIEVE) {
state = TaskState.FINISHED;
// 任務(wù)完成后進(jìn)對(duì)外部服務(wù)進(jìn)行通知
activityService.notifyFinished(taskId);
taskManager.release(taskId);
} else if (actionType == ActionType.STOP) {
state = TaskState.PAUSED;
} else if (actionType == ActionType.EXPIRE) {
state = TaskState.EXPIRED;
}
} else if (state == TaskState.PAUSED) {
if (actionType == ActionType.START) {
state = TaskState.ONGOING;
} else if (actionType == ActionType.EXPIRE) {
state = TaskState.EXPIRED;
}
}
}
}
class Task {
private Long taskId;
// 任務(wù)的默認(rèn)狀態(tài)為初始化
private TaskState state = TaskState.INIT;
// 活動(dòng)服務(wù)
private ActivityService activityService;
// 任務(wù)管理器
private TaskManager taskManager;
// 使用條件分支進(jìn)行任務(wù)更新
public void updateState(ActionType actionType) {
if (state == TaskState.INIT) {
if (actionType == ActionType.START) {
state = TaskState.ONGOING;
}
} else if (state == TaskState.ONGOING) {
if (actionType == ActionType.ACHIEVE) {
state = TaskState.FINISHED;
// 任務(wù)完成后進(jìn)對(duì)外部服務(wù)進(jìn)行通知
activityService.notifyFinished(taskId);
taskManager.release(taskId);
} else if (actionType == ActionType.STOP) {
state = TaskState.PAUSED;
} else if (actionType == ActionType.EXPIRE) {
state = TaskState.EXPIRED;
}
} else if (state == TaskState.PAUSED) {
if (actionType == ActionType.START) {
state = TaskState.ONGOING;
} else if (actionType == ActionType.EXPIRE) {
state = TaskState.EXPIRED;
}
}
}
}
在上述的實(shí)現(xiàn)中,小明在updateState方法中完成了2個(gè)重要的功能:
- 接收不同的行為,然后更新當(dāng)前任務(wù)的狀態(tài);
- 當(dāng)任務(wù)過(guò)期時(shí),通知任務(wù)所屬的活動(dòng)和任務(wù)管理器。
誠(chéng)然,隨著小明的系統(tǒng)開(kāi)發(fā)能力和代碼質(zhì)量意識(shí)的提升,他能夠認(rèn)識(shí)到這種功能設(shè)計(jì)存在缺陷?!袄蠋?,我的代碼還是和之前說(shuō)的那樣,不夠優(yōu)雅。”“哦,你自己說(shuō)說(shuō)看有什么問(wèn)題?”“第一,方法中使用條件判斷來(lái)控制語(yǔ)句,但是當(dāng)條件復(fù)雜或者狀態(tài)太多時(shí),條件判斷語(yǔ)句會(huì)過(guò)于臃腫,可讀性差,且不具備擴(kuò)展性,維護(hù)難度也大。且增加新的狀態(tài)時(shí)要添加新的if-else語(yǔ)句,這違背了開(kāi)閉原則,不利于程序的擴(kuò)展?!崩蠋煴硎就?,小明接著說(shuō):“第二,任務(wù)類(lèi)不夠高內(nèi)聚,它在通知實(shí)現(xiàn)中感知了其他領(lǐng)域或模塊的模型,如活動(dòng)和任務(wù)管理器,這樣代碼的耦合度太高,不利于擴(kuò)展?!崩蠋熧澷p地說(shuō)道:“很好,你有意識(shí)能夠自主發(fā)現(xiàn)代碼問(wèn)題所在,已經(jīng)是很大的進(jìn)步了?!薄澳沁@個(gè)問(wèn)題應(yīng)該怎么去解決呢?”小明繼續(xù)發(fā)問(wèn)?!斑@個(gè)同樣可以通過(guò)設(shè)計(jì)模式去優(yōu)化。首先是狀態(tài)流轉(zhuǎn)的控制可以使用狀態(tài)模式,其次,任務(wù)完成時(shí)的通知可以用到觀察者模式?!笔盏街甘竞螅∶黢R上去學(xué)習(xí)了狀態(tài)模式的結(jié)構(gòu):
狀態(tài)模式:對(duì)有狀態(tài)的對(duì)象,把復(fù)雜的“判斷邏輯”提取到不同的狀態(tài)對(duì)象中,允許狀態(tài)對(duì)象在其內(nèi)部狀態(tài)發(fā)生改變時(shí)改變其行為。狀態(tài)模式包含以下主要角色:
- 環(huán)境類(lèi)(Context)角色:也稱為上下文,它定義了客戶端需要的接口,內(nèi)部維護(hù)一個(gè)當(dāng)前狀態(tài),并負(fù)責(zé)具體狀態(tài)的切換。
- 抽象狀態(tài)(State)角色:定義一個(gè)接口,用以封裝環(huán)境對(duì)象中的特定狀態(tài)所對(duì)應(yīng)的行為,可以有一個(gè)或多個(gè)行為。
- 具體狀態(tài)(Concrete State)角色:實(shí)現(xiàn)抽象狀態(tài)所對(duì)應(yīng)的行為,并且在需要的情況下進(jìn)行狀態(tài)切換。
根據(jù)狀態(tài)模式的定義,小明將TaskState枚舉類(lèi)擴(kuò)展成多個(gè)狀態(tài)類(lèi),并具備完成狀態(tài)的流轉(zhuǎn)的能力;然后優(yōu)化了任務(wù)類(lèi)的實(shí)現(xiàn):
// 任務(wù)狀態(tài)抽象接口
interface State {
// 默認(rèn)實(shí)現(xiàn),不做任何處理
default void update(Task task, ActionType actionType) {
// do nothing
}
}
// 任務(wù)初始狀態(tài)
class TaskInit implements State {
@Override
public void update(Task task, ActionType actionType) {
if (actionType == ActionType.START) {
task.setState(new TaskOngoing());
}
}
}
// 任務(wù)進(jìn)行狀態(tài)
class TaskOngoing implements State {
private ActivityService activityService;
private TaskManager taskManager;
@Override
public void update(Task task, ActionType actionType) {
if (actionType == ActionType.ACHIEVE) {
task.setState(new TaskFinished());
// 通知
activityService.notifyFinished(taskId);
taskManager.release(taskId);
} else if (actionType == ActionType.STOP) {
task.setState(new TaskPaused());
} else if (actionType == ActionType.EXPIRE) {
task.setState(new TaskExpired());
}
}
}
// 任務(wù)暫停狀態(tài)
class TaskPaus
文章名稱:設(shè)計(jì)模式二三事
網(wǎng)頁(yè)地址:http://www.5511xx.com/article/cophpje.html


咨詢
建站咨詢
