您好,登錄后才能下訂單哦!
本篇內(nèi)容介紹了“如何使用行為型模式”的有關(guān)知識(shí),在實(shí)際案例的操作過(guò)程中,不少人都會(huì)遇到這樣的困境,接下來(lái)就讓小編帶領(lǐng)大家學(xué)習(xí)一下如何處理這些情況吧!希望大家仔細(xì)閱讀,能夠?qū)W有所成!
狀態(tài)模式的好處是將與特定狀態(tài)相關(guān)的行為局部化,并且將不同狀態(tài)的行為分割開(kāi)來(lái)。
將特定相關(guān)的行為都放入一個(gè)對(duì)象中,由于所有與狀態(tài)相關(guān)的代碼都存在于某個(gè)ConcreteState
中,所以通過(guò)定義新的子類可以很容易地增加新的狀態(tài)和轉(zhuǎn)換。
Context: 上下文,定義了客戶程序需要的接口并維護(hù)一個(gè)狀態(tài)類。
State: 狀態(tài)類,定義一個(gè)接口以封裝上下文環(huán)境的一個(gè)特定狀態(tài)相關(guān)的行為,與狀態(tài)相關(guān)的操作委托給具體的state對(duì)象進(jìn)行處理。
Concrete State: 具體狀態(tài)類
采用的例子是王者里面的,要么在打團(tuán)要么在打團(tuán)的路上,這就涉及到了狀態(tài)的轉(zhuǎn)換。
State
public interface State { void handle(Context context); }
Concrete State
回城狀態(tài)
public class ConcreteStateBack implements State{ @Override public void handle(Context context) { System.out.println("沒(méi)狀態(tài)了,回城補(bǔ)個(gè)狀態(tài)先"); context.setState(new ConcreteStateWalk()); } }
打團(tuán)狀態(tài)
public class ConcreteStateFight implements State{ @Override public void handle(Context context) { System.out.println("大招一按,蒼穹一開(kāi),雙手一放,要么黑屏,要么五殺"); context.setState(new ConcreteStateBack()); } }
打團(tuán)的路上狀態(tài)
public class ConcreteStateWalk implements State{ @Override public void handle(Context context) { System.out.println("狀態(tài)已滿,等我集合打團(tuán)"); context.setState(new ConcreteStateFight()); } }
失敗狀態(tài)
public class ConcreteStateDefeated implements State{ @Override public void handle(Context context) { System.out.println("Defeated!!!"); } }
Context
public class Context { private State state; public State getState() { return state; } public void setState(State state) { this.state = state; } public Context(State state) { this.state = state; } public void request() { state.handle(this); } }
Client
public class Client { public static void main(String[] args) { Context context = new Context(new ConcreteStateWalk()); for (int i = 0; i < 8; i++) { context.request(); } context.setState(new ConcreteStateDefeated()); context.request(); } }
策略模式是一種定義一系列算法的方法,但是這些方法最終完成的都是相同的工作,只是策略不同,也就是實(shí)現(xiàn)不同。
它可以以相同的方式來(lái)調(diào)用所有的算法,減少了各種算法類和使用算法類之間的耦合。
Context: 上下文,內(nèi)部有個(gè)strategy屬性,并且能夠通過(guò)其調(diào)用策略
Strategy: 策略接口或者抽象類,定義了策略的方法
Concrete Strategy: 具體的策略
還是拿游戲舉例,最終的目的都是為了贏,但是具體的方式可能要根據(jù)對(duì)方的陣容做出改變。
Context
public class Context { Strategy strategy; public Context(Strategy strategy) { this.strategy = strategy; } public void invokeStrategy() { strategy.play(); } }
Strategy
public interface Strategy { void play(); }
Concrete Strategy
public class ConcreteStrategyAttackMid implements Strategy{ @Override public void play() { System.out.println("集合進(jìn)攻中路"); } }
public class ConcreteStrategyGank implements Strategy{ @Override public void play() { System.out.println("轉(zhuǎn)線抓人推塔"); } }
public class ConcreteStrategyInvade implements Strategy{ @Override public void play() { System.out.println("入侵野區(qū)"); } }
Client
public class Client { public static void main(String[] args) { Context context = new Context(new ConcreteStrategyAttackMid()); context.invokeStrategy(); context = new Context(new ConcreteStrategyGank()); context.invokeStrategy(); context = new Context(new ConcreteStrategyInvade()); context.invokeStrategy(); } }
模板方法就是定義一個(gè)操作的算法的骨架,而將一些步驟延遲到子類種。模板方法使得子類可以不改變一個(gè)算法的結(jié)構(gòu)即可重定義改算法的某些特定步驟。
簡(jiǎn)而言之就是,我給你一個(gè)模板,步驟是哪些,但是具體怎么實(shí)現(xiàn)看個(gè)人。
Abstract Class: 實(shí)現(xiàn)一個(gè)模板方法,定義了算法的估計(jì)
Concrete Class: 對(duì)模板中各個(gè)算法的不同實(shí)現(xiàn)
都知道電腦的組裝都是有一個(gè)模板的,需要哪些零件都是固定的,不同的是零件的采用不同。這樣我們就可以把組裝作為一個(gè)行為模板給封裝起來(lái)。
Abstract Class
public abstract class AbstractClass { public void assemble() { System.out.println("開(kāi)始模板組裝電腦"); cpu(); radiating(); screen(); } public abstract void cpu(); public abstract void radiating(); public abstract void screen(); }
Concrete Class
public class ConcreteClassMid extends AbstractClass{ @Override public void cpu() { System.out.println("Intel 10900K, Intel偶爾的神"); } @Override public void radiating() { System.out.println("雙銅散熱管"); } @Override public void screen() { System.out.println("75hz高素質(zhì)屏幕"); } }
public class ConcreteClassTop extends AbstractClass{ @Override public void cpu() { System.out.println("AMD5950X,AMD永遠(yuǎn)的神"); } @Override public void radiating() { System.out.println("雙銅散熱管加液冷散熱"); } @Override public void screen() { System.out.println("144hz電競(jìng)屏"); } }
Client
public class Client { public static void main(String[] args) { AbstractClass templateToAssembleComputer = new ConcreteClassMid(); templateToAssembleComputer.assemble(); templateToAssembleComputer = new ConcreteClassTop(); templateToAssembleComputer.assemble(); } }
到這里有沒(méi)有印象之前說(shuō)過(guò)的建造者模式,可以說(shuō)非常相似,因?yàn)榻ㄔ煺吣J骄褪墙柚四0宸椒J絹?lái)實(shí)現(xiàn)的。
在不破壞封裝的前提下,捕獲一個(gè)對(duì)象的內(nèi)部狀態(tài),并在該對(duì)象之外保存這個(gè)狀態(tài),這樣可以在以后將對(duì)象恢復(fù)到原先保存的狀態(tài)。備忘錄嘛,也是比較形象的,就像我們解題的時(shí)候可以把過(guò)程寫下來(lái)看,最后可以按照步驟檢查,知道哪里出了問(wèn)題,從那里恢復(fù)解題的過(guò)程,從而正確解題。
Originator: 發(fā)起者是我們需要記住狀態(tài)的對(duì)象,以便在某個(gè)時(shí)刻恢復(fù)它。
Caretaker: 管理者是負(fù)責(zé)觸發(fā)發(fā)起者的變化或者觸發(fā)發(fā)起者返回先前狀態(tài)動(dòng)作的類。
Memento: 備忘錄是負(fù)責(zé)存儲(chǔ)發(fā)起者內(nèi)部狀態(tài)的類。備忘錄提供了設(shè)置狀態(tài)和獲取狀態(tài)的方法,但是這些方法應(yīng)該對(duì)管理者隱藏。
**場(chǎng)景:**大家都玩過(guò)超級(jí)瑪麗,合金彈頭,或者i wanna這類的游戲叭。有什么組成呢,一個(gè)是玩家(Originator),一個(gè)是經(jīng)常需要存檔的檔案(Memento),還有一個(gè)是游戲后臺(tái)管理(Caretaker)。
對(duì)于玩家而言,可以存檔(setMemento和createMemento),也可以讀檔,恢復(fù)到上次存檔的位置(restoreMemento)。
Originator
(玩家)
public class OriginatorPlayer { private String name; private String status; public OriginatorPlayer(String name) { this.name = name; } //交給游戲后臺(tái)處理 1 public MementoGameState create() { return new MementoGameState(status); } //玩家存檔 2 public void save(String status) { this.status = status; System.out.println("存檔:" + status); } public void read(MementoGameState gameState) { this.status = gameState.getGameStatus(); System.out.println("讀檔:" + status); } }
其實(shí)我覺(jué)得1,2步是可以合起來(lái)寫成下面這樣子
public MementoGameState save(String status) { this.status = status; System.out.println("存檔:" + status); return new MementoGameState(status); }
Memento
(游戲狀態(tài))
public class MementoGameState { private String gameStatus = ""; public MementoGameState(String gameStatus) { this.gameStatus = gameStatus; } public String getGameStatus() { return gameStatus; } }
Caretaker
(后臺(tái)管理)
public class CaretakerGameManager { MementoGameState gameState; public MementoGameState getGameState() { return gameState; } //這是后臺(tái)真正存檔 public void setGameState(MementoGameState gameState) { System.out.println("系統(tǒng)已經(jīng)存檔: " + gameState.getGameStatus()); this.gameState = gameState; } }
Client
public class Client { public static void main(String[] args) { OriginatorPlayer cutey = new OriginatorPlayer("cutey"); CaretakerGameManager gameManager = new CaretakerGameManager(); //玩家自己點(diǎn)了存檔,但是不一定存成功 cutey.save("第一關(guān)"); //后臺(tái)要處理玩家的存檔的請(qǐng)求(imperfect.create()) gameManager.setGameState(cutey.create()); cutey.save("第二關(guān)"); gameManager.setGameState(cutey.create()); //這種情況就是可能我們點(diǎn)了存檔,還沒(méi)有成功就退出了 cutey.save("第三關(guān)"); //讀取檔案 cutey.read(gameManager.getGameState()); } }
仔細(xì)地看代碼會(huì)發(fā)現(xiàn),說(shuō)到底講備忘錄,備忘的是不是就是游戲角色的狀態(tài),為此專門有一個(gè)類(GameState)來(lái)存這個(gè)狀態(tài)。
在恢復(fù)狀態(tài)的時(shí)候,在讀取備忘錄中的狀態(tài)賦給游戲角色中。所以歸根結(jié)底都是如何保存游戲角色的狀態(tài),然后在需要的時(shí)候可以恢復(fù)。
那是不是一定要新建一個(gè)類來(lái)幫我們保存呢,如果我們直接保存的是上個(gè)階段的游戲角色(而不是單純的游戲狀態(tài)),然后讀檔的時(shí)候直接讀上個(gè)階段的游戲角色可以嗎?
也就是發(fā)起人(Originator)也充當(dāng)了備忘錄(Memento)肯定是可以的。
又來(lái)想,要存的是自己,要拷貝的是自己來(lái)充當(dāng)備忘錄,為了節(jié)省空間,會(huì)用到之后講的原型模式 。
到這里的話,普通的備忘錄模式就已經(jīng)講完了,下面要講的都是基于普通上進(jìn)行的改進(jìn),可看可不看。
玩家:
public class PlayerC implements Cloneable { private String name; private String state; public PlayerC(String name) { this.name = name; } public String getState() { return state; } public void setState(String state) { System.out.println("玩家進(jìn)行到:" + state); this.state = state; } //存檔,存的是自己 public PlayerC create() { System.out.println("玩家存檔:" + this.clone().getState()); return this.clone(); } //讀檔 public void play(PlayerC playerC) { System.out.println("玩家讀檔:" + playerC.getState()); setState(playerC.getState()); } //克隆自己 @Override public PlayerC clone() { try { return (PlayerC) super.clone(); } catch (CloneNotSupportedException e) { e.printStackTrace(); } return null; } }
后臺(tái)管理:
public class GameManagerC { PlayerC playerC; public PlayerC getPlayerC() { return playerC; } //真正的存檔 public void setPlayerC(PlayerC playerC) { this.playerC = playerC; } }
Client:
public class ClientC { public static void main(String[] args) throws CloneNotSupportedException { PlayerC playerC = new PlayerC("perfext"); GameManagerC gameManagerC = new GameManagerC(); //分析和普通模式一樣,就不再贅述 playerC.setState("%10"); gameManagerC.setPlayerC(playerC.create()); playerC.setState("%20"); gameManagerC.setPlayerC(playerC.create()); playerC.setState("%30"); playerC.play(gameManagerC.getPlayerC()); } }
上面甚至還不是最簡(jiǎn)潔的,因?yàn)槠鋵?shí)我們存檔還是要在后臺(tái)管理類里面存,當(dāng)然這是希望看到的。想想后臺(tái)管理類的作用是干嘛的,是用來(lái)管理備忘錄的,既然備忘錄類都可以省略,后臺(tái)管理類自然也可以精簡(jiǎn)掉。
也就是說(shuō),玩家的狀態(tài)保存在玩家的內(nèi)部,但是這與定義不符合,在一開(kāi)始我特意加粗了”在該對(duì)象之外保存這個(gè)狀態(tài)“。所以說(shuō)本篇博客就不再講述這種方式的實(shí)現(xiàn),也比較簡(jiǎn)單(提示:在玩家類內(nèi)部聲明一個(gè)成員變量作為恢復(fù)的游戲角色)。
上面講的都是比較簡(jiǎn)單的備忘錄模式,還有兩種比較常用的,一種是一個(gè)角色有多個(gè)狀態(tài)同時(shí)需要備忘,先講這種,另外一種賣個(gè)關(guān)子。
場(chǎng)景:一個(gè)角色有多個(gè)狀態(tài),那還是拿打游戲的例子,不過(guò)游戲角色不僅僅是第幾關(guān)。新的游戲角色有,打到了哪個(gè)階段,等級(jí)是多少以及裝備三個(gè)狀態(tài)。
玩家:
public class PlayerS { private String name; private String equipment; private String schedule; private String grade; //存檔 public GameStateS save() { System.out.println("玩家存檔:" + toString()); return new GameStateS(this); } //讀檔案,從保存的狀態(tài)中一個(gè)個(gè)讀出來(lái) public void read(GameStateS gameStateS) { equipment = (String) gameStateS.getStates().get("equipment"); schedule = (String) gameStateS.getStates().get("schedule"); grade = (String) gameStateS.getStates().get("grade"); System.out.println("玩家讀檔:" + toString()); } public PlayerS(String name) { this.name = name; } /** * 省略 * 1.toString方法,用來(lái)方便打印 * 2.set方法,用來(lái)方便玩家存檔 * 3.get方法,方便存儲(chǔ)玩家的狀態(tài) */ }
游戲狀態(tài)(檔案):
public class GameStateS { //多狀態(tài),所以用hashmap來(lái)保存 private HashMap<String, Object> states = new HashMap<>(); //保存著玩家的狀態(tài) public GameStateS(PlayerS playerS) { states.put("schedule", playerS.getSchedule()); states.put("grade", playerS.getGrade()); states.put("equipment", playerS.getEquipment()); } public HashMap<String, Object> getStates() { return states; } }
后臺(tái)管理:
public class GameManagerS { private GameStateS gameStateS; public GameStateS getGameStateS() { return gameStateS; } //真正存檔 public void setGameStateS(GameStateS gameStateS) { System.out.println("系統(tǒng)已經(jīng)存檔!"); this.gameStateS = gameStateS; } }
Client:
public class ClientS { public static void main(String[] args) { PlayerS player = new PlayerS("perfext"); GameManagerS gameManagerS = new GameManagerS(); player.setSchedule("10%"); player.setEquipment("2件套"); player.setGrade("6級(jí)"); gameManagerS.setGameStateS(player.save()); player.setSchedule("30%"); player.setEquipment("4件套"); player.setGrade("10級(jí)"); gameManagerS.setGameStateS(player.save()); player.setSchedule("80%"); player.setEquipment("6件套"); player.setGrade("15級(jí)"); System.out.println("忘記存檔了!已經(jīng)打到了:"); System.out.println(player.toString()); player.read(gameManagerS.getGameStateS()); } }
本質(zhì)還是那樣,沒(méi)有太大變化,就是把狀態(tài)用hashmap做了一個(gè)封裝。
目前為止,對(duì)于上面所講的所有備忘錄模式,不知道各位小伙伴有沒(méi)有發(fā)現(xiàn)一個(gè)問(wèn)題,就是在恢復(fù)的時(shí)候,只能恢復(fù)特定的狀態(tài)(一般是最后備忘的那個(gè)狀態(tài))。
但是在現(xiàn)實(shí)社會(huì)中,在碼字或者打代碼的時(shí)候總你能夠ctrl + z(撤銷)好幾次,可以撤銷回滿意的狀態(tài)。下面要講的應(yīng)該可以幫助到你。
原諒我不知道怎么高大上專業(yè)的表述這種備忘錄模式。
**場(chǎng)景:**再用游戲講的話不太清楚,接下來(lái)打字員(Originator)打字,內(nèi)容(Memento)交給電腦(Caretaker)保存來(lái)演示。
打字員:
public class Typist { private String name; private String word; //最新的狀態(tài) private List<String> content = new ArrayList<>(); //所有的狀態(tài) int len = 0; //狀態(tài)的位置,根據(jù)這個(gè)位置來(lái)讀取 public Typist(String name) { this.name = name; } public void setWord(String word) { this.word = word; } //保存 public TypeContent save() { content.add(word); System.out.println("打字員保存:" + word); len++; //長(zhǎng)度+1 return new TypeContent(content); } //讀取 public void read(TypeContent typeContent) { content = typeContent.getTypeContent(); System.out.println("目前顯示:" + content.get(--len)); //讀完后長(zhǎng)度-1 } }
內(nèi)容:
public class TypeContent { private List<String> typeContent = new ArrayList<>(); //保存用戶寫的字 public TypeContent(List<String> typeContent) { this.typeContent = typeContent; } public List<String> getTypeContent() { return typeContent; } }
電腦:
public class Computer { private TypeContent typeContent; public TypeContent getTypeContent() { return typeContent; } //真正保存用戶寫的字 public void setTypeContent(TypeContent typeContent) { this.typeContent = typeContent; } }
Client:
public class ClientM { public static void main(String[] args) { Typist perfext = new Typist("perfext"); Computer computer = new Computer(); perfext.setWord("abcd"); computer.setTypeContent(perfext.save()); perfext.setWord("efg"); computer.setTypeContent(perfext.save()); perfext.setWord("hijkl"); computer.setTypeContent(perfext.save()); perfext.setWord("mnopq"); computer.setTypeContent(perfext.save()); perfext.read(computer.getTypeContent()); //模擬ctrl+z System.out.println("撤銷:"); perfext.read(computer.getTypeContent()); System.out.println("撤銷:"); perfext.read(computer.getTypeContent()); System.out.println("撤銷:"); perfext.read(computer.getTypeContent()); } }
“如何使用行為型模式”的內(nèi)容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關(guān)的知識(shí)可以關(guān)注億速云網(wǎng)站,小編將為大家輸出更多高質(zhì)量的實(shí)用文章!
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。