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

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


咨詢
建站咨詢
