1. 程式人生 > >Java與設計模式-狀態模式

Java與設計模式-狀態模式

維護 chan str else 開關 進行 private 接下來 csdn

 

概念:狀態模式把所研究的對象的行為包裝在不同的狀態對象裏。每個狀態對象都屬於一個抽象狀態類的一個子類。

狀態模式的意圖是讓一個對象在其內部狀態改變的時候。其行為也隨之改變,也就是不同狀態相應不同的行為。狀態模式的示意性類圖例如以下所看到的:

技術分享

UML類圖:Context:能夠理解成控制類

State是狀態接口

ConcreteStateA和ConcreteStateB能夠覺得是接口的實現,也就是詳細的狀態實現類。

使用場景:對象的狀態決定對象的行為,在執行時依據狀態動態調整對象的行為。

代碼中有復雜的if else推斷。且這些分支推斷和狀態有關系。

實際場景:(1)電視開關機狀態,電視開機狀態下才幹夠進行各種操作,關機狀態下,不能進行各項操作。

(2)WIFI狀態,WIFI開狀態下能夠連接WIFI,關閉狀態不可進行操作。

(3)登錄狀態,這個在開發中較為經常使用。一般在進入系統實現分享轉發等操作時要先推斷用戶的登錄狀態,若已經登錄則可進行操作。否則提示用戶登錄。

我們來實現場景1.

首先創建一個狀態接口(相應UML類圖中的State接口):

package com.state.demo;

public interface TvState {
	/**
	 * 電視狀態的接口,裏面提供四種方法
	 */
	void nextChanel();
	void preChanel();
	void turnUp();
	void turnDown();

}

接下來兩個實現類(相應UML類圖中ConcreteStateA):

package com.state.demo;

public class PowerOnState implements TvState {
	/**
	 * 開機狀態下,遙控器button有效
	 */

	@Override
	public void nextChanel() {

		System.out.println("---------下一頻道-----------------------");
	}

	@Override
	public void preChanel() {
		System.out.println("---------上一頻道-----------------------");
	}

	@Override
	public void turnUp() {
		System.out.println("---------音量增大-----------------------");
	}

	@Override
	public void turnDown() {
		System.out.println("---------音量減小-----------------------");
	}

}


實現類2(相應UML類圖中ConcreteStateB):

package com.state.demo;

public class PowerOffState implements TvState {
	/**
	 * 關機狀態下。全部button無效
	 */

	@Override
	public void nextChanel() {
		System.out.println("---------關機狀態不可用。請先開機-----------------------");
	}

	@Override
	public void preChanel() {
		System.out.println("---------關機狀態不可用,請先開機-----------------------");
	}

	@Override
	public void turnUp() {
		System.out.println("---------關機狀態不可用。請先開機-----------------------");
	}

	@Override
	public void turnDown() {
		System.out.println("---------關機狀態不可用。請先開機-----------------------");
	}

}


接下來控制類(相應UML類圖中Context):

package com.state.demo;

public class TvController {
	
	TvState tvState=null;
	public void setTvState(TvState tvState) {
		this.tvState = tvState;
	}
	/**
	 * 開機
	 */
	public void turnOnTv(){
		
		setTvState(new PowerOnState());
		System.out.println("--------開機啦---------------");
	}
	/**
	 * 關機
	 */
	public void turnOffTv(){
		
		setTvState(new PowerOffState());
		System.out.println("--------關機啦---------------");
	}
	/**
	 * 下一頻道
	 */
	public void nextChanel(){
		tvState.nextChanel();
	}
	
	public void preChanel(){
		tvState.preChanel();
	}
	
	public void turnUp(){
		tvState.turnUp();
	}
	public void turnDown(){
		tvState.turnDown();
	}
}


最後,編寫一個測試類,測試以上代碼:

package com.state.demo;

public class TestClass {

	public static void main(String[] args) {

		TvController tvController=new TvController();//創建一個控制類
		tvController.turnOnTv();//首先開機
		tvController.nextChanel();
		tvController.turnDown();
		tvController.turnOffTv();//關機
		
		tvController.turnDown();//關機後功能不再提供
	}

}

執行實比例如以下:

技術分享

這裏有些邏輯小問題,就是在已經開機的狀態下,用戶再次調用開機要進行提示。這時我們能夠在控制類中增加例如以下代碼;

package com.state.demo;

public class TvController {
	private boolean isTvOn=false;
	TvState tvState=null;
	public void setTvState(TvState tvState) {
		this.tvState = tvState;
	}
	/**
	 * 開機
	 */
	public void turnOnTv(){
		if(!isTvOn){
			isTvOn=true;
			setTvState(new PowerOnState());
			System.out.println("--------開機啦---------------");
		}else{
			isTvOn=true;
			System.out.println("--------已經開機了,不要再按了---------------");
		}
		
	}
	/**
	 * 關機
	 */
	public void turnOffTv(){
		if(isTvOn){
			isTvOn=false;
		setTvState(new PowerOffState());
		System.out.println("--------關機啦---------------");
		}else{
			isTvOn=false;
			System.out.println("-------已經關機啦,不要再按了---------------");
		}
	}
	/**
	 * 下一頻道
	 */
	public void nextChanel(){
		tvState.nextChanel();
	}
	
	public void preChanel(){
		tvState.preChanel();
	}
	
	public void turnUp(){
		tvState.turnUp();
	}
	public void turnDown(){
		tvState.turnDown();
	}
}


做一個開機標識,每次調用方法之前進行推斷就可以。

這時再次執行測試類:

package com.state.demo;

public class TestClass {

	public static void main(String[] args) {

		TvController tvController=new TvController();//創建一個控制類
		tvController.turnOnTv();//首先開機
		tvController.turnOnTv();//首先開機
		tvController.nextChanel();
		tvController.turnDown();
		tvController.turnOffTv();//關機
		tvController.turnOffTv();//關機
		
		tvController.turnDown();//關機後功能不再提供
	}

}


執行例如以下:

技術分享

總結:控制類持有系統狀態,但控制類不直接處理行為,行為在狀態的實現類中實現;

用戶直接操作控制類,直接和控制類交互,不直接操作狀態實現類,這樣就有一個職責的分離,有利於系統維護。

喜歡的朋友請關註我,謝謝。

Java與設計模式-狀態模式