国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

【十五】設計模式~~~行為型模式~~~狀態(tài)模式(Java)

這篇具有很好參考價值的文章主要介紹了【十五】設計模式~~~行為型模式~~~狀態(tài)模式(Java)。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點擊"舉報違法"按鈕提交疑問。

【學習難度:★★★☆☆,使用頻率:★★★☆☆】

4.1. 模式動機

  • 在很多情況下,一個對象的行為取決于一個或多個動態(tài)變化的屬性,這樣的屬性叫做狀態(tài),這樣的對象叫做有狀態(tài)的(stateful)對象,這樣的對象狀態(tài)是從事先定義好的一系列值中取出的。當一個這樣的對象與外部事件產(chǎn)生互動時,其內(nèi)部狀態(tài)就會改變,從而使得系統(tǒng)的行為也隨之發(fā)生變化。
  • 在UML中可以使用狀態(tài)圖來描述對象狀態(tài)的變化。

案例1

??????“人有悲歡離合,月有陰晴圓缺”,包括人在內(nèi),很多事物都具有多種狀態(tài),而且在不同狀態(tài)下會具有不同的行為,這些狀態(tài)在特定條件下還將發(fā)生相互轉(zhuǎn)換。就像水,它可以凝固成冰,也可以受熱蒸發(fā)后變成水蒸汽,水可以流動,冰可以雕刻,蒸汽可以擴散。我們可以用UML狀態(tài)圖來描述H2O的三種狀態(tài),如圖1所示:
【十五】設計模式~~~行為型模式~~~狀態(tài)模式(Java)

??????在軟件系統(tǒng)中,有些對象也像水一樣具有多種狀態(tài),這些狀態(tài)在某些情況下能夠相互轉(zhuǎn)換,而且對象在不同的狀態(tài)下也將具有不同的行為。為了更好地對這些具有多種狀態(tài)的對象進行設計,我們可以使用一種被稱之為狀態(tài)模式的設計模式,

案例2(銀行系統(tǒng)中的賬戶類設計)

??????Sunny軟件公司欲為某銀行開發(fā)一套信用卡業(yè)務系統(tǒng),銀行賬戶(Account)是該系統(tǒng)的核心類之一,通過分析,Sunny軟件公司開發(fā)人員發(fā)現(xiàn)在該系統(tǒng)中,賬戶存在三種狀態(tài),且在不同狀態(tài)下賬戶存在不同的行為,具體說明如下:

  • (1) 、如果賬戶中余額大于等于0,則賬戶的狀態(tài)為正常狀態(tài)(Normal State),此時用戶既可以向該賬戶存款也可以從該賬戶取款;
  • (2)、 如果賬戶中余額小于0,并且大于-2000,則賬戶的狀態(tài)為透支狀態(tài)(Overdraft State),此時用戶既可以向該賬戶存款也可以從該賬戶取款,但需要按天計算利息;
  • (3) 、如果賬戶中余額等于-2000,那么賬戶的狀態(tài)為受限狀態(tài)(Restricted State),此時用戶只能向該賬戶存款,不能再從中取款,同時也將按天計算利息;
  • (4) 、根據(jù)余額的不同,以上三種狀態(tài)可發(fā)生相互轉(zhuǎn)換。

??????Sunny軟件公司開發(fā)人員對銀行賬戶類進行分析,繪制了如圖2所示UML狀態(tài)圖:
【十五】設計模式~~~行為型模式~~~狀態(tài)模式(Java)

??????在圖2中,NormalState表示正常狀態(tài),OverdraftState表示透支狀態(tài),RestrictedState表示受限狀態(tài),在這三種狀態(tài)下賬戶對象擁有不同的行為,方法deposit()用于存款,withdraw()用于取款,computeInterest()用于計算利息,stateCheck()用于在每一次執(zhí)行存款和取款操作后根據(jù)余額來判斷是否要進行狀態(tài)轉(zhuǎn)換并實現(xiàn)狀態(tài)轉(zhuǎn)換,相同的方法在不同的狀態(tài)中可能會有不同的實現(xiàn)。為了實現(xiàn)不同狀態(tài)下對象的各種行為以及對象狀態(tài)之間的相互轉(zhuǎn)換,Sunny軟件公司開發(fā)人員設計了一個較為龐大的賬戶類Account,其中部分代碼如下所示:

class Account {
	private String state; //狀態(tài)
	private int balance; //余額
	......
	
	//存款操作	
	public void deposit() {
		//存款
		stateCheck();	
	}
	
	//取款操作
	public void withdraw() {
		if (state.equalsIgnoreCase("NormalState") || state.equalsIgnoreCase("OverdraftState ")) {
			//取款
			stateCheck();
		}
		else {
			//取款受限
		}
	}
	
	//計算利息操作
	public void computeInterest() {
		if(state.equalsIgnoreCase("OverdraftState") || state.equalsIgnoreCase("RestrictedState ")) {
			//計算利息
		}
	}
	
	//狀態(tài)檢查和轉(zhuǎn)換操作
	public void stateCheck() {
		if (balance >= 0) {
			state = "NormalState";
		}
		else if (balance > -2000 && balance < 0) {
			state = "OverdraftState";
		}
		else if (balance == -2000) {
			state = "RestrictedState";
		}
        else if (balance < -2000) {
            //操作受限
        }
	}
	......
}

??????分析上述代碼,我們不難發(fā)現(xiàn)存在如下幾個問題:

  • (1) 幾乎每個方法中都包含狀態(tài)判斷語句,以判斷在該狀態(tài)下是否具有該方法以及在特定狀態(tài)下該方法如何實現(xiàn),導致代碼非常冗長,可維護性較差;
  • (2) 擁有一個較為復雜的stateCheck()方法,包含大量的if…else if…else…語句用于進行狀態(tài)轉(zhuǎn)換,代碼測試難度較大,且不易于維護;
  • (3) 系統(tǒng)擴展性較差,如果需要增加一種新的狀態(tài),如凍結狀態(tài)(Frozen State,在該狀態(tài)下既不允許存款也不允許取款),需要對原有代碼進行大量修改,擴展起來非常麻煩。

??????為了解決這些問題,我們可以使用狀態(tài)模式,在狀態(tài)模式中,我們將對象在每一個狀態(tài)下的行為和狀態(tài)轉(zhuǎn)移語句封裝在一個個狀態(tài)類中,通過這些狀態(tài)類來分散冗長的條件轉(zhuǎn)移語句,讓系統(tǒng)具有更好的靈活性和可擴展性,狀態(tài)模式可以在一定程度上解決上述問題。

4.2. 模式定義

??????狀態(tài)模式(State Pattern) :允許一個對象在其內(nèi)部狀態(tài)改變時改變它的行為,對象看起來似乎修改了它的類。其別名為狀態(tài)對象(Objects for States),狀態(tài)模式是一種對象行為型模式

4.3. 模式結構

狀態(tài)模式包含如下角色:

  • Context: 環(huán)境類,環(huán)境類又稱為上下文類,它是擁有多種狀態(tài)的對象。由于環(huán)境類的狀態(tài)存在多樣性且在不同狀態(tài)下對象的行為有所不同,因此將狀態(tài)獨立出去形成單獨的狀態(tài)類。在環(huán)境類中維護一個抽象狀態(tài)類State的實例,這個實例定義當前狀態(tài),在具體實現(xiàn)時,它是一個State子類的對象。
  • State: 抽象狀態(tài)類,它用于定義一個接口以封裝與環(huán)境類的一個特定狀態(tài)相關的行為,在抽象狀態(tài)類中聲明了各種不同狀態(tài)對應的方法,而在其子類中實現(xiàn)類這些方法,由于不同狀態(tài)下對象的行為可能不同,因此在不同子類中方法的實現(xiàn)可能存在不同,相同的方法可以寫在抽象狀態(tài)類中。
  • ConcreteState: 具體狀態(tài)類,它是抽象狀態(tài)類的子類,每一個子類實現(xiàn)一個與環(huán)境類的一個狀態(tài)相關的行為,每一個具體狀態(tài)類對應環(huán)境的一個具體狀態(tài),不同的具體狀態(tài)類其行為有所不同。
    【十五】設計模式~~~行為型模式~~~狀態(tài)模式(Java)

??????在狀態(tài)模式中,我們將對象在不同狀態(tài)下的行為封裝到不同的狀態(tài)類中,為了讓系統(tǒng)具有更好的靈活性和可擴展性,同時對各狀態(tài)下的共有行為進行封裝,我們需要對狀態(tài)進行抽象,引入了抽象狀態(tài)類角色,其典型代碼如下所示:

abstract class State {
    //聲明抽象業(yè)務方法,不同的具體狀態(tài)類可以不同的實現(xiàn)
	public abstract void handle();
}

??????在抽象狀態(tài)類的子類即具體狀態(tài)類中實現(xiàn)了在抽象狀態(tài)類中聲明的業(yè)務方法,不同的具體狀態(tài)類可以提供完全不同的方法實現(xiàn),在實際使用時,在一個狀態(tài)類中可能包含多個業(yè)務方法,如果在具體狀態(tài)類中某些業(yè)務方法的實現(xiàn)完全相同,可以將這些方法移至抽象狀態(tài)類,實現(xiàn)代碼的復用,典型的具體狀態(tài)類代碼如下所示:

class ConcreteState extends State {
	public void handle() {
		//方法具體實現(xiàn)代碼
	}
}

??????環(huán)境類維持一個對抽象狀態(tài)類的引用,通過setState()方法可以向環(huán)境類注入不同的狀態(tài)對象,再在環(huán)境類的業(yè)務方法中調(diào)用狀態(tài)對象的方法,典型代碼如下所示:

class Context {
	private State state; //維持一個對抽象狀態(tài)對象的引用
	private int value; //其他屬性值,該屬性值的變化可能會導致對象狀態(tài)發(fā)生變化
 
    //設置狀態(tài)對象
	public void setState(State state) {
		this.state = state;
	}
 
	public void request() {
		//其他代碼
		state.handle(); //調(diào)用狀態(tài)對象的業(yè)務方法
		//其他代碼
	}
}

??????環(huán)境類實際上是真正擁有狀態(tài)的對象,我們只是將環(huán)境類中與狀態(tài)有關的代碼提取出來封裝到專門的狀態(tài)類中。在狀態(tài)模式結構圖中,環(huán)境類Context與抽象狀態(tài)類State之間存在單向關聯(lián)關系,在Context中定義了一個State對象。在實際使用時,它們之間可能存在更為復雜的關系,State與Context之間可能也存在依賴或者關聯(lián)關系。
??????在狀態(tài)模式的使用過程中,一個對象的狀態(tài)之間還可以進行相互轉(zhuǎn)換,通常有兩種實現(xiàn)狀態(tài)轉(zhuǎn)換的方式:
??????(1) 統(tǒng)一由環(huán)境類來負責狀態(tài)之間的轉(zhuǎn)換,此時,環(huán)境類還充當了狀態(tài)管理器(State Manager)角色,在環(huán)境類的業(yè)務方法中通過對某些屬性值的判斷實現(xiàn)狀態(tài)轉(zhuǎn)換,還可以提供一個專門的方法用于實現(xiàn)屬性判斷和狀態(tài)轉(zhuǎn)換,如下代碼片段所示:


      public void changeState() {
		//判斷屬性值,根據(jù)屬性值進行狀態(tài)轉(zhuǎn)換
      if (value == 0) {
			this.setState(new ConcreteStateA());
		}
		else if (value == 1) {
			this.setState(new ConcreteStateB());
		}

	}

??????(2) 由具體狀態(tài)類來負責狀態(tài)之間的轉(zhuǎn)換,可以在具體狀態(tài)類的業(yè)務方法中判斷環(huán)境類的某些屬性值再根據(jù)情況為環(huán)境類設置新的狀態(tài)對象,實現(xiàn)狀態(tài)轉(zhuǎn)換,同樣,也可以提供一個專門的方法來負責屬性值的判斷和狀態(tài)轉(zhuǎn)換。此時,狀態(tài)類與環(huán)境類之間就將存在依賴或關聯(lián)關系,因為狀態(tài)類需要訪問環(huán)境類中的屬性值,如下代碼片段所示:

	……
      public void changeState(Context ctx) {
		//根據(jù)環(huán)境對象中的屬性值進行狀態(tài)轉(zhuǎn)換
      if (ctx.getValue() == 1) {
			ctx.setState(new ConcreteStateB());
		}
		else if (ctx.getValue() == 2) {
			ctx.setState(new ConcreteStateC());
		}
        ......
	}
    ……

4.4. 時序圖

【十五】設計模式~~~行為型模式~~~狀態(tài)模式(Java)

4.5. 代碼分析

??????Sunny軟件公司開發(fā)人員使用狀態(tài)模式來解決賬戶狀態(tài)的轉(zhuǎn)換問題,客戶端只需要執(zhí)行簡單的存款和取款操作,系統(tǒng)根據(jù)余額將自動轉(zhuǎn)換到相應的狀態(tài),其基本結構如圖4所示:
【十五】設計模式~~~行為型模式~~~狀態(tài)模式(Java)

4.5.1 生產(chǎn)

??????在圖4中,Account充當環(huán)境類角色,AccountState充當抽象狀態(tài)角色,NormalState、OverdraftState和RestrictedState充當具體狀態(tài)角色。完整代碼如下所示:

package com.zyz.demo;

/**
 * @author zyz
 * @version 1.0
 * @data 2023/5/28 21:50
 * @Description:
 */


//銀行賬戶:環(huán)境類

class Account {
    private AccountState state; //維持一個對抽象狀態(tài)對象的引用
    private String owner; //開戶名
    private double balance = 0; //賬戶余額

    public Account(String owner,double init) {
        this.owner = owner;
        this.balance = balance;
        this.state = new NormalState(this); //設置初始狀態(tài)
        System.out.println(this.owner + "開戶,初始金額為" + init);
        System.out.println("---------------------------------------------");
    }

    public double getBalance() {
        return this.balance;
    }

    public void setBalance(double balance) {
        this.balance = balance;
    }

    public void setState(AccountState state) {
        this.state = state;
    }

    public void deposit(double amount) {
        System.out.println(this.owner + "存款" + amount);
        state.deposit(amount); //調(diào)用狀態(tài)對象的deposit()方法
        System.out.println("現(xiàn)在余額為"+ this.balance);
        System.out.println("現(xiàn)在帳戶狀態(tài)為"+ this.state.getClass().getName());
        System.out.println("---------------------------------------------");
    }

    public void withdraw(double amount) {
        System.out.println(this.owner + "取款" + amount);
        state.withdraw(amount); //調(diào)用狀態(tài)對象的withdraw()方法
        System.out.println("現(xiàn)在余額為"+ this.balance);
        System.out.println("現(xiàn)在帳戶狀態(tài)為"+ this. state.getClass().getName());
        System.out.println("---------------------------------------------");
    }

    public void computeInterest()
    {
        state.computeInterest(); //調(diào)用狀態(tài)對象的computeInterest()方法
    }
}


//抽象狀態(tài)類

abstract class AccountState {
    protected Account acc;
    public abstract void deposit(double amount);
    public abstract void withdraw(double amount);
    public abstract void computeInterest();
    public abstract void stateCheck();
}


//正常狀態(tài):具體狀態(tài)類

class NormalState extends AccountState {
    public NormalState(Account acc) {
        this.acc = acc;
    }

    public NormalState(AccountState state) {
        this.acc = state.acc;
    }

    @Override
    public void deposit(double amount) {
        acc.setBalance(acc.getBalance() + amount);
        stateCheck();
    }
    @Override
    public void withdraw(double amount) {
        acc.setBalance(acc.getBalance() - amount);
        stateCheck();
    }

    @Override
    public void computeInterest()
    {
        System.out.println("正常狀態(tài),無須支付利息!");
    }

    /**
     * 狀態(tài)轉(zhuǎn)換
     */
    @Override
    public void stateCheck() {
        if (acc.getBalance() > -2000 && acc.getBalance() <= 0) {
            acc.setState(new OverdraftState(this));
        }
        else if (acc.getBalance() == -2000) {
            acc.setState(new RestrictedState(this));
        }
        else if (acc.getBalance() < -2000) {
            System.out.println("操作受限!");
        }
    }
}

//透支狀態(tài):具體狀態(tài)類

class OverdraftState extends AccountState
{
    public OverdraftState(AccountState state) {
        this.acc = state.acc;
    }

    @Override
    public void deposit(double amount) {
        acc.setBalance(acc.getBalance() + amount);
        stateCheck();
    }

    @Override
    public void withdraw(double amount) {
        acc.setBalance(acc.getBalance() - amount);
        stateCheck();
    }

    @Override
    public void computeInterest() {
        System.out.println("計算利息!");
    }

    /**
     * 狀態(tài)轉(zhuǎn)換
     */
    @Override
    public void stateCheck() {
        if (acc.getBalance() > 0) {
            acc.setState(new NormalState(this));
        }
        else if (acc.getBalance() == -2000) {
            acc.setState(new RestrictedState(this));
        }
        else if (acc.getBalance() < -2000) {
            System.out.println("操作受限!");
        }
    }
}

//受限狀態(tài):具體狀態(tài)類

class RestrictedState extends AccountState {
    public RestrictedState(AccountState state) {
        this.acc = state.acc;
    }

    @Override
    public void deposit(double amount) {
        acc.setBalance(acc.getBalance() + amount);
        stateCheck();
    }

    @Override
    public void withdraw(double amount) {
        System.out.println("帳號受限,取款失敗");
    }

    @Override
    public void computeInterest() {
        System.out.println("計算利息!");
    }

    /**
     * 狀態(tài)轉(zhuǎn)換
     */
    @Override
    public void stateCheck() {
        if(acc.getBalance() > 0) {
            acc.setState(new NormalState(this));
        }
        else if(acc.getBalance() > -2000) {
            acc.setState(new OverdraftState(this));
        }
    }
}

4.5.2 客戶端

package com.zyz.demo;

/**
 * @author zyz
 * @version 1.0
 * @data 2023/5/28 21:53
 * @Description:
 */
public class Client {
    public static void main(String args[]) {
        Account acc = new Account("段譽",0.0);
        acc.deposit(1000);
        acc.withdraw(2000);
        acc.deposit(3000);
        acc.withdraw(4000);
        acc.withdraw(1000);
        acc.computeInterest();
    }
}

4.5.3 測試結果

【十五】設計模式~~~行為型模式~~~狀態(tài)模式(Java)

4.6. 模式分析

  • 狀態(tài)模式描述了對象狀態(tài)的變化以及對象如何在每一種狀態(tài)下表現(xiàn)出不同的行為。
  • 狀態(tài)模式的關鍵是引入了一個抽象類來專門表示對象的狀態(tài),這個類我們叫做抽象狀態(tài)類,而對象的每一種具體狀態(tài)類都繼承了該類,并在不同具體狀態(tài)類中實現(xiàn)了不同狀態(tài)的行為,包括各種狀態(tài)之間的轉(zhuǎn)換。
    在狀態(tài)模式結構中需要理解環(huán)境類與抽象狀態(tài)類的作用:
  • 環(huán)境類實際上就是擁有狀態(tài)的對象,環(huán)境類有時候可以充當狀態(tài)管理器(State Manager)的角色,可以在環(huán)境類中對狀態(tài)進行切換操作。
  • 抽象狀態(tài)類可以是抽象類,也可以是接口,不同狀態(tài)類就是繼承這個父類的不同子類,狀態(tài)類的產(chǎn)生是由于環(huán)境類存在多個狀態(tài),同時還滿足兩個條件: 這些狀態(tài)經(jīng)常需要切換,在不同的狀態(tài)下對象的行為不同。因此可以將不同對象下的行為單獨提取出來封裝在具體的狀態(tài)類中,使得環(huán)境類對象在其內(nèi)部狀態(tài)改變時可以改變它的行為,對象看起來似乎修改了它的類,而實際上是由于切換到不同的具體狀態(tài)類實現(xiàn)的。由于環(huán)境類可以設置為任一具體狀態(tài)類,因此它針對抽象狀態(tài)類進行編程,在程序運行時可以將任一具體狀態(tài)類的對象設置到環(huán)境類中,從而使得環(huán)境類可以改變內(nèi)部狀態(tài),并且改變行為。

4.7. 實例

TCPConnection
??????這個示例來自《設計模式》,展示了一個簡化版的TCP協(xié)議實現(xiàn); TCP連接的狀態(tài)有多種可能,狀態(tài)之間的轉(zhuǎn)換有相應的邏輯前提; 這是使用狀態(tài)模式的場合;
結構圖:
【十五】設計模式~~~行為型模式~~~狀態(tài)模式(Java)

時序圖
【十五】設計模式~~~行為型模式~~~狀態(tài)模式(Java)

4.8. 優(yōu)點

狀態(tài)模式的優(yōu)點

  • 封裝了轉(zhuǎn)換規(guī)則。
  • 枚舉可能的狀態(tài),在枚舉狀態(tài)之前需要確定狀態(tài)種類。
  • 將所有與某個狀態(tài)有關的行為放到一個類中,并且可以方便地增加新的狀態(tài),只需要改變對象狀態(tài)即可改變對象的行為。
  • 允許狀態(tài)轉(zhuǎn)換邏輯與狀態(tài)對象合成一體,而不是某一個巨大的條件語句塊。
  • 可以讓多個環(huán)境對象共享一個狀態(tài)對象,從而減少系統(tǒng)中對象的個數(shù)。

4.9. 缺點

狀態(tài)模式的缺點

  • 狀態(tài)模式的使用必然會增加系統(tǒng)類和對象的個數(shù)。
  • 狀態(tài)模式的結構與實現(xiàn)都較為復雜,如果使用不當將導致程序結構和代碼的混亂。
  • 狀態(tài)模式對“開閉原則”的支持并不太好,對于可以切換狀態(tài)的狀態(tài)模式,增加新的狀態(tài)類需要修改那些負責狀態(tài)轉(zhuǎn)換的源代碼,否則無法切換到新增狀態(tài);而且修改某個狀態(tài)類的行為也需修改對應類的源代碼。

4.10. 適用環(huán)境

在以下情況下可以使用狀態(tài)模式:

  • 對象的行為依賴于它的狀態(tài)(屬性)并且可以根據(jù)它的狀態(tài)改變而改變它的相關行為。
  • 代碼中包含大量與對象狀態(tài)有關的條件語句,這些條件語句的出現(xiàn),會導致代碼的可維護性和靈活性變差,不能方便地增加和刪除狀態(tài),使客戶類與類庫之間的耦合增強。在這些條件語句中包含了對象的行為,而且這些條件對應于對象的各種狀態(tài)。

4.11. 模式應用

??????狀態(tài)模式在工作流或游戲等類型的軟件中得以廣泛使用,甚至可以用于這些系統(tǒng)的核心功能設計,如在政府OA辦公系統(tǒng)中,一個批文的狀態(tài)有多種:尚未辦理;正在辦理;正在批示;正在審核;已經(jīng)完成等各種狀態(tài),而且批文狀態(tài)不同時對批文的操作也有所差異。使用狀態(tài)模式可以描述工作流對象(如批文)的狀態(tài)轉(zhuǎn)換以及不同狀態(tài)下它所具有的行為。

4.12. 模式擴展

共享狀態(tài)

  • 在有些情況下多個環(huán)境對象需要共享同一個狀態(tài),如果希望在系統(tǒng)中實現(xiàn)多個環(huán)境對象實例共享一個或多個狀態(tài)對象,那么需要將這些狀態(tài)對象定義為環(huán)境的靜態(tài)成員對象。

簡單狀態(tài)模式與可切換狀態(tài)的狀態(tài)模式

  1. 簡單狀態(tài)模式:簡單狀態(tài)模式是指狀態(tài)都相互獨立,狀態(tài)之間無須進行轉(zhuǎn)換的狀態(tài)模式,這是最簡單的一種狀態(tài)模式。對于這種狀態(tài)模式,每個狀態(tài)類都封裝與狀態(tài)相關的操作,而無須關心狀態(tài)的切換,可以在客戶端直接實例化狀態(tài)類,然后將狀態(tài)對象設置到環(huán)境類中。如果是這種簡單的狀態(tài)模式,它遵循“開閉原則”,在客戶端可以針對抽象狀態(tài)類進行編程,而將具體狀態(tài)類寫到配置文件中,同時增加新的狀態(tài)類對原有系統(tǒng)也不造成任何影響。
  2. 可切換狀態(tài)的狀態(tài)模式:大多數(shù)的狀態(tài)模式都是可以切換狀態(tài)的狀態(tài)模式,在實現(xiàn)狀態(tài)切換時,在具體狀態(tài)類內(nèi)部需要調(diào)用環(huán)境類Context的setState()方法進行狀態(tài)的轉(zhuǎn)換操作,在具體狀態(tài)類中可以調(diào)用到環(huán)境類的方法,因此狀態(tài)類與環(huán)境類之間通常還存在關聯(lián)關系或者依賴關系。通過在狀態(tài)類中引用環(huán)境類的對象來回調(diào)環(huán)境類的setState()方法實現(xiàn)狀態(tài)的切換。在這種可以切換狀態(tài)的狀態(tài)模式中,增加新的狀態(tài)類可能需要修改其他某些狀態(tài)類甚至環(huán)境類的源代碼,否則系統(tǒng)無法切換到新增狀態(tài)。

4.13. 總結

  • 狀態(tài)模式允許一個對象在其內(nèi)部狀態(tài)改變時改變它的行為,對象看起來似乎修改了它的類。其別名為狀態(tài)對象,狀態(tài)模式是一種對象行為型模式。
  • 狀態(tài)模式包含三個角色:環(huán)境類又稱為上下文類,它是擁有狀態(tài)的對象,在環(huán)境類中維護一個抽象狀態(tài)類State的實例,這個實例定義當前狀態(tài),在具體實現(xiàn)時,它是一個State子類的對象,可以定義初始狀態(tài);抽象狀態(tài)類用于定義一個接口以封裝與環(huán)境類的一個特定狀態(tài)相關的行為;具體狀態(tài)類是抽象狀態(tài)類的子類,每一個子類實現(xiàn)一個與環(huán)境類的一個狀態(tài)相關的行為,每一個具體狀態(tài)類對應環(huán)境的一個具體狀態(tài),不同的具體狀態(tài)類其行為有所不同。
  • 狀態(tài)模式描述了對象狀態(tài)的變化以及對象如何在每一種狀態(tài)下表現(xiàn)出不同的行為。
  • 狀態(tài)模式的主要優(yōu)點在于封裝了轉(zhuǎn)換規(guī)則,并枚舉可能的狀態(tài),它將所有與某個狀態(tài)有關的行為放到一個類中,并且可以方便地增加新的狀態(tài),只需要改變對象狀態(tài)即可改變對象的行為,還可以讓多個環(huán)境對象共享一個狀態(tài)對象,從而減少系統(tǒng)中對象的個數(shù);其缺點在于使用狀態(tài)模式會增加系統(tǒng)類和對象的個數(shù),且狀態(tài)模式的結構與實現(xiàn)都較為復雜,如果使用不當將導致程序結構和代碼的混亂,對于可以切換狀態(tài)的狀態(tài)模式不滿足“開閉原則”的要求。
  • 狀態(tài)模式適用情況包括:對象的行為依賴于它的狀態(tài)(屬性)并且可以根據(jù)它的狀態(tài)改變而改變它的相關行為;代碼中包含大量與對象狀態(tài)有關的條件語句,這些條件語句的出現(xiàn),會導致代碼的可維護性和靈活性變差,不能方便地增加和刪除狀態(tài),使客戶類與類庫之間的耦合增強。

4.14.處理對象的多種狀態(tài)及其相互轉(zhuǎn)換

使用環(huán)境類實現(xiàn)狀態(tài)轉(zhuǎn)換
??????在狀態(tài)模式中實現(xiàn)狀態(tài)轉(zhuǎn)換時,具體狀態(tài)類可通過調(diào)用環(huán)境類Context的setState()方法進行狀態(tài)的轉(zhuǎn)換操作,也可以統(tǒng)一由環(huán)境類Context來實現(xiàn)狀態(tài)的轉(zhuǎn)換。此時,增加新的具體狀態(tài)類可能需要修改其他具體狀態(tài)類或者環(huán)境類的源代碼,否則系統(tǒng)無法轉(zhuǎn)換到新增狀態(tài)。但是對于客戶端來說,無須關心狀態(tài)類,可以為環(huán)境類設置默認的狀態(tài)類,而將狀態(tài)的轉(zhuǎn)換工作交給具體狀態(tài)類或環(huán)境類來完成,具體的轉(zhuǎn)換細節(jié)對于客戶端而言是透明的。

??????在上面的“銀行賬戶狀態(tài)轉(zhuǎn)換”實例中,我們通過具體狀態(tài)類來實現(xiàn)狀態(tài)的轉(zhuǎn)換,在每一個具體狀態(tài)類中都包含一個stateCheck()方法,在該方法內(nèi)部實現(xiàn)狀態(tài)的轉(zhuǎn)換,除此之外,我們還可以通過環(huán)境類來實現(xiàn)狀態(tài)轉(zhuǎn)換,環(huán)境類作為一個狀態(tài)管理器,統(tǒng)一實現(xiàn)各種狀態(tài)之間的轉(zhuǎn)換操作

??????下面通過一個包含循環(huán)狀態(tài)的簡單實例來說明如何使用環(huán)境類實現(xiàn)狀態(tài)轉(zhuǎn)換:

??????Sunny軟件公司某開發(fā)人員欲開發(fā)一個屏幕放大鏡工具,其具體功能描述如下:
用戶單擊“放大鏡”按鈕之后屏幕將放大一倍,再點擊一次“放大鏡”按鈕屏幕再放大一倍,第三次點擊該按鈕后屏幕將還原到默認大小。
??????可以考慮使用狀態(tài)模式來設計該屏幕放大鏡工具,我們定義三個屏幕狀態(tài)類NormalState、LargerState和LargestState來對應屏幕的三種狀態(tài),分別是正常狀態(tài)、二倍放大狀態(tài)和四倍放大狀態(tài),屏幕類Screen充當環(huán)境類,其結構如圖6所示:
【十五】設計模式~~~行為型模式~~~狀態(tài)模式(Java)

本實例核心代碼如下所示:

package com.zyz.demo1;

/**
 * @author zyz
 * @version 1.0
 * @data 2023/5/28 22:12
 * @Description:
 */

//屏幕類

class Screen {
    //枚舉所有的狀態(tài),currentState表示當前狀態(tài)
    private State currentState, normalState, largerState, largestState;

    public Screen() {
        this.normalState = new NormalState(); //創(chuàng)建正常狀態(tài)對象
        this.largerState = new LargerState(); //創(chuàng)建二倍放大狀態(tài)對象
        this.largestState = new LargestState(); //創(chuàng)建四倍放大狀態(tài)對象
        this.currentState = normalState; //設置初始狀態(tài)
        this.currentState.display();
    }

    public void setState(State state) {
        this.currentState = state;
    }

    /**
     * 單擊事件處理方法,封轉(zhuǎn)了對狀態(tài)類中業(yè)務方法的調(diào)用和狀態(tài)的轉(zhuǎn)換
     */
    public void onClick() {
        if (this.currentState == normalState) {
            this.setState(largerState);
            this.currentState.display();
        }
        else if (this.currentState == largerState) {
            this.setState(largestState);
            this.currentState.display();
        }
        else if (this.currentState == largestState) {
            this.setState(normalState);
            this.currentState.display();
        }
    }
}


//抽象狀態(tài)類

abstract class State {
    public abstract void display();
}

//正常狀態(tài)類

class NormalState extends State{
    @Override
    public void display() {
        System.out.println("正常大小!");
    }
}


//二倍狀態(tài)類

class LargerState extends State{
    @Override
    public void display() {
        System.out.println("二倍大??!");
    }
}


//四倍狀態(tài)類

class LargestState extends State{
    @Override
    public void display() {
        System.out.println("四倍大小!");
    }


}

??????在上述代碼中,所有的狀態(tài)轉(zhuǎn)換操作都由環(huán)境類Screen來實現(xiàn),此時,環(huán)境類充當了狀態(tài)管理器角色。如果需要增加新的狀態(tài),例如“八倍狀態(tài)類”,需要修改環(huán)境類,這在一定程度上違背了“開閉原則”,但對其他狀態(tài)類沒有任何影響。
??????編寫如下客戶端代碼進行測試:

package com.zyz.demo1;

/**
 * @author zyz
 * @version 1.0
 * @data 2023/5/28 22:13
 * @Description: 客戶端
 */
class Client {
    public static void main(String args[]) {
        Screen screen = new Screen();
        screen.onClick();
        screen.onClick();
        screen.onClick();
    }
}

輸出結果如下:
【十五】設計模式~~~行為型模式~~~狀態(tài)模式(Java)文章來源地址http://www.zghlxwxcb.cn/news/detail-468170.html

到了這里,關于【十五】設計模式~~~行為型模式~~~狀態(tài)模式(Java)的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權/違法違規(guī)/事實不符,請點擊違法舉報進行投訴反饋,一經(jīng)查實,立即刪除!

領支付寶紅包贊助服務器費用

相關文章

  • 行為型設計模式——狀態(tài)模式

    行為型設計模式——狀態(tài)模式

    狀態(tài)模式是比較簡單的設計模式,它的主要作用是減少代碼中大量的 if-else 或者 switch-case 等邏輯判斷(俗稱屎山)。它將每個狀態(tài)定義為一個類,而每個狀態(tài)類有自己對應的方法,因此當需要根據(jù)狀態(tài)執(zhí)行邏輯代碼時不需要寫大量的if-else判斷是哪個狀態(tài)然后執(zhí)行對應的邏輯

    2024年02月02日
    瀏覽(30)
  • 設計模式行為型-狀態(tài)模式

    設計模式行為型-狀態(tài)模式

    狀態(tài)模式是一種行為型設計模式,用于處理對象在不同狀態(tài)下的行為變化。它將對象的行為封裝在不同狀態(tài)類中,通過狀態(tài)的切換實現(xiàn)不同行為的觸發(fā)。 本文將介紹狀態(tài)模式的基本概念、應用場景以及優(yōu)勢與適用性。 實現(xiàn)具體狀態(tài)類 具體工作類: 上下文類包含狀態(tài)對象的引

    2024年02月10日
    瀏覽(25)
  • 設計模式行為型——狀態(tài)模式

    設計模式行為型——狀態(tài)模式

    ? 目錄 狀態(tài)模式的定義 狀態(tài)模式的實現(xiàn) 狀態(tài)模式角色 狀態(tài)模式類圖 狀態(tài)模式舉例 狀態(tài)模式代碼實現(xiàn) 狀態(tài)模式的特點 優(yōu)點 缺點 使用場景 注意事項 實際應用 ? ? ? ?在軟件開發(fā)過程中,應用程序中的部分對象可能會根據(jù)不同的情況做出不同的行為,把這種對象稱為有狀態(tài)

    2024年02月14日
    瀏覽(24)
  • 設計模式—行為型模式之狀態(tài)模式

    設計模式—行為型模式之狀態(tài)模式

    狀態(tài)(State)模式:對有狀態(tài)的對象,把復雜的“判斷邏輯”提取到不同的狀態(tài)對象中,允許狀態(tài)對象在其內(nèi)部狀態(tài)發(fā)生改變時改變其行為。 狀態(tài)模式包含以下主要角色: 環(huán)境類(Context)角色:也稱為上下文,它定義了客戶端需要的接口,內(nèi)部維護一個當前狀態(tài),并負責具

    2024年01月15日
    瀏覽(20)
  • 笨蛋學設計模式行為型模式-狀態(tài)模式【20】

    8.7.1概念 ? 狀態(tài)模式是指對象在運行時可以根據(jù)內(nèi)部狀態(tài)的不同而改變它們的行為,該模式將內(nèi)部狀態(tài)的行為封裝為不同的具體狀態(tài)類中,并將狀態(tài)轉(zhuǎn)換邏輯委托給這些狀態(tài)類來處理,當對象的內(nèi)部狀態(tài)發(fā)生變化時,它會自動切換到對應的狀態(tài)類,從而改變其行為。 8.7.2場景

    2024年01月23日
    瀏覽(21)
  • 【地鐵上的設計模式】--行為型模式:狀態(tài)模式

    什么是狀態(tài)模式 狀態(tài)模式是一種行為模式,它允許對象在其內(nèi)部狀態(tài)發(fā)生改變時改變其行為。在狀態(tài)模式中,將狀態(tài)定義為獨立的對象,并將對象在不同狀態(tài)下的行為委托給具有相應行為的狀態(tài)對象。當對象的狀態(tài)發(fā)生變化時,它將使用不同的狀態(tài)對象來執(zhí)行不同的操作,從

    2024年02月04日
    瀏覽(25)
  • 【設計模式】第22節(jié):行為型模式之“狀態(tài)模式”

    【設計模式】第22節(jié):行為型模式之“狀態(tài)模式”

    狀態(tài)模式一般用來實現(xiàn)狀態(tài)機,而狀態(tài)機常用在游戲、工作流引擎等系統(tǒng)開發(fā)中。不過,狀態(tài)機的實現(xiàn)方式有多種,除了狀態(tài)模式,比較常用的還有分支邏輯法和查表法。該模式允許對象內(nèi)部狀態(tài)改變使改變它的行為。 行為隨狀態(tài)而改變 條件、分支語句的替代者 交通信號燈

    2024年02月06日
    瀏覽(20)
  • 3.8設計模式——State 狀態(tài)模式(行為型)

    3.8設計模式——State 狀態(tài)模式(行為型)

    允許一個對象在其內(nèi)部狀態(tài)改變時改變它的行為。對象看起來似乎修改了它的類。 Context(上下文)定義客戶感興趣的接口;維護一個ConcreteState子類的實例,這個實例定義當前狀態(tài)。 State(狀態(tài))定義一個接口以封裝與Context的一個特定狀態(tài)相關的行為。 ConcreteState(具體狀態(tài)

    2024年04月26日
    瀏覽(27)
  • 軟件設計模式與體系結構-設計模式-行為型軟件設計模式-狀態(tài)模式

    軟件設計模式與體系結構-設計模式-行為型軟件設計模式-狀態(tài)模式

    與策略模式類似,狀態(tài)模式將不同狀態(tài)下的行為封裝在不同的類中,每個類代表一個狀態(tài) 狀態(tài)模式的組成 Context:定義了與客戶程序的接口,它保持了一個concreteState的代表現(xiàn)在狀態(tài)的實例 State:定義了狀態(tài)接口,它的各個子類封裝了在各種不同狀態(tài)下的行為 ConcreteState子類:

    2024年02月13日
    瀏覽(25)
  • 【設計模式——學習筆記】23種設計模式——狀態(tài)模式State(原理講解+應用場景介紹+案例介紹+Java代碼實現(xiàn))

    【設計模式——學習筆記】23種設計模式——狀態(tài)模式State(原理講解+應用場景介紹+案例介紹+Java代碼實現(xiàn))

    請編寫程序完成APP抽獎活動具體要求如下: 假如每參加一次這個活動要扣除用戶50積分,中獎概率是10% 獎品數(shù)量固定,抽完就不能抽獎 活動有四個狀態(tài): 可以抽獎、不能抽獎、發(fā)放獎品和獎品領完,活動的四個狀態(tài)轉(zhuǎn)換關系圖如下 一開始的狀態(tài)為“不能抽獎”,當扣除50積分

    2024年02月12日
    瀏覽(29)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領取紅包,優(yōu)惠每天領

二維碼1

領取紅包

二維碼2

領紅包