溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

如何使用行為型模式

發(fā)布時(shí)間:2021-10-12 10:51:30 來(lái)源:億速云 閱讀:127 作者:iii 欄目:編程語(yǔ)言

本篇內(nèi)容介紹了“如何使用行為型模式”的有關(guān)知識(shí),在實(shí)際案例的操作過(guò)程中,不少人都會(huì)遇到這樣的困境,接下來(lái)就讓小編帶領(lǐng)大家學(xué)習(xí)一下如何處理這些情況吧!希望大家仔細(xì)閱讀,能夠?qū)W有所成!

狀態(tài)模式

狀態(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)類

狀態(tài)模式UML

如何使用行為型模式

采用的例子是王者里面的,要么在打團(tuán)要么在打團(tuán)的路上,這就涉及到了狀態(tài)的轉(zhuǎn)換。

如何使用行為型模式

狀態(tài)模式

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: 具體的策略

狀態(tài)模式UML

如何使用行為型模式

狀態(tài)模式

還是拿游戲舉例,最終的目的都是為了贏,但是具體的方式可能要根據(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)

模板方法UML

如何使用行為型模式

模板方法

都知道電腦的組裝都是有一個(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)。

備忘錄UML

如何使用行為型模式

普通備忘錄模式:

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),可看可不看。

基于clone的備忘錄模式:

玩家:

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)子。

多狀態(tài)的備忘錄模式:

場(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í)用文章!

向AI問(wèn)一下細(xì)節(jié)

免責(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)容。

AI