設計模式 - 狀態模式 (Behavioral Patterns - State Design Pattern)
前言
在介紹狀態模式前,必須先講解一下狀態模式與策略模式的關係。
先看兩張圖
策略模式
狀態模式
我們可以看到兩張類別圖可以說是一模一樣,但是差別在哪呢?
策略模式
- 可以讓呼叫端轉換不同的演算法
- 他算是主動的使用我們的function並且抽換
狀態模式
- 給物件不同的狀態,並且限制他只能在這狀態做哪些事情
- 他算是被動的被控制只能使用那些function
舉例
策略模式
以策略模式文章中的技能,技能Service可以控管要呼叫哪個Skill物件使用,去使用就適合策略模式
狀態模式
角色今天可能會有禁咒、石化,那我們需要先把角色可以做的事情抽出來(攻擊、移動、技能)創出一個行為介面,再依不同的狀態實做這個介面,而這些物件則可以在實作中根據狀態,限制這些行為。
範例
英雄今天可能會被施加石化、禁咒,那我們看一下狀態模式如何讓我們的程式碼,抽象話
- 讓正常、石化、禁咒狀態實作State介面
- 英雄呼叫State介面的方法(可抽換不同的狀態實作)
- 再由Context(設定不同的狀態)
interface HeroState {
void run();
void useSkill();
void attack();
}
class PetrochemicalState implements HeroState {
@Override
public void run() {
System.out.println("Your are a stone so you can't do anything");
}
@Override
public void useSkill() {
System.out.println("Your are a stone so you can't do anything");
}
@Override
public void attack() {
System.out.println("Your are a stone so you can't do anything");
}
}
class CursedState implements HeroState {
@Override
public void run() {
System.out.println("You are running");
}
@Override
public void useSkill() {
System.out.println("Your are cursed so you can't use skill");
}
@Override
public void attack() {
System.out.println("Your are attacking");
}
}
class NormalState implements HeroState {
@Override
public void run() {
System.out.println("You are running");
}
@Override
public void useSkill() {
System.out.println("Your are using skill");
}
@Override
public void attack() {
System.out.println("Your are attacking");
}
}
class Hero {
HeroState heroState;
public void attack() {
heroState.attack();
}
public void run() {
heroState.run();
}
public void useSkill() {
heroState.useSkill();
}
public void setState(HeroState state) {
this.heroState = state;
}
}
class HeroActionService {
public void doAllAction(Hero hero) {
hero.attack();
hero.run();
hero.useSkill();
}
}
public class State {
public static void main(String[] args) {
Hero hero = new Hero();
HeroActionService heroActionService = new HeroActionService();
System.out.println("Normal state");
hero.setState(new NormalState());
heroActionService.doAllAction(hero);
hero.setState(new CursedState());
heroActionService.doAllAction(hero);
hero.setState(new PetrochemicalState());
heroActionService.doAllAction(hero);
}
}
結論
-
狀態模式適合用來表達,當下此物件不同狀態時可執行方法的差異
- 石化甚麼都不可以做
- 禁咒不可施法、但其他都可以
-
策略模式,適合讓物件決定去做甚麼
- 今天要用治療或是攻擊技能
-
兩者最大差別在於意圖
- 一個是我這個情況可以做哪些事情
- 一個是接下來我要做甚麼(沒有情況)
留言
張貼留言