1. 程式人生 > >我所理解的設計模式(C++實現)——狀態模式(State Pattern)

我所理解的設計模式(C++實現)——狀態模式(State Pattern)

概述:

     看看我們平時用的開關,同樣一個開關他有2種狀態:開和關,當她處於不同的狀態的時候她的行為是不一樣的,比如當她是開著的時候,你按她一下,她就變成了關閉狀態,她是關著的時候按她一下,她就變成了開著的狀態。看上去就像是改變了它的類一樣,其實我們開發者都知道,我們裡面用到了if-else,但是當碰到更多狀態時就會造成很多很多if-else,設計和維護就相當的複雜,我們將要學習的狀態模式就是允許一個物件在其內部狀態改變時改變它的行為,使物件看起來似乎修改了它的類。 

類圖和例項:


上下文環境(Context):它定義了客戶程式需要的介面並維護一個具體狀態角色的例項,將與狀態相關的操作委託給當前的Concrete State物件來處理。

抽象狀態(State):定義一個介面以封裝使用上下文環境的的一個特定狀態相關的行為。

具體狀態(Concrete State):實現抽象狀態定義的介面。 

這裡我們舉星際爭霸裡的坦克作為例子,它不架起來的時候可以攻擊,可以移動。架起來的時候攻擊增強,但是不能移動:

#include <iostream>
class SiegeTank;
class ISiegeTankState
{
public:
	virtual void move(int x, int y) = 0;
	virtual void attack() = 0;
};

class SiegeState : public ISiegeTankState
{
public:
	SiegeState(SiegeTank* pTank): m_pTank(pTank){}
	
	virtual void move(int x, int y)
	{
		std::cout << "Can't move in siege mode." << std::endl;
	}

	virtual void attack()
	{
		std::cout << "Attacking for 40" << std::endl;
	}

private:
	SiegeTank* m_pTank;
};

class TankState : public ISiegeTankState
{
public:
	TankState(SiegeTank* pTank): m_pTank(pTank){}

	virtual void move(int x, int y)
	{
		std::cout << "Move to (" << x << ", " << y << ")" << std::endl;
	}

	virtual void attack()
	{
		std::cout << "Attacking for 20" << std::endl;
	}

private:
	SiegeTank* m_pTank;
};

class SiegeTank
{
public:
	SiegeTank()
	{
		m_pTankState = new TankState(this);
		m_pSiegeState = new SiegeState(this);
		m_pSiegeTankState = m_pTankState;
	}

	void enterTankMode()
	{
		m_pSiegeTankState = m_pTankState;
		std::cout << "Switch to tank mode" << std::endl;
	}

	void enterSiegeMode()
	{
		m_pSiegeTankState = m_pSiegeState;
		std::cout << "Switch to siege mode" << std::endl;
	}

public:
	void attack()
	{
		m_pSiegeTankState->attack();
	}

	void move(int x, int y)
	{
		m_pSiegeTankState->move(x, y);
	}

private:
	void setState(ISiegeTankState* pSiegeTankMode)
	{
		m_pSiegeTankState = pSiegeTankMode;
	}

private:
	TankState* m_pTankState;
	SiegeState* m_pSiegeState;
	ISiegeTankState* m_pSiegeTankState;
};

int main()
{
	SiegeTank tank;
	tank.enterTankMode();
	tank.attack();
	tank.move(1, 1);

	tank.enterSiegeMode();
	tank.attack();
	tank.move(2, 2);

	tank.enterTankMode();
	tank.attack();
	tank.move(3, 3);

	return 0;
}

解決的問題:

狀態模式主要解決的是當控制一個物件狀態裝換的條件表示式過於複雜時的情況。把狀態的判斷邏輯轉移到表示不同狀態的一系列類中,可以把複雜的判斷邏輯簡單化。
當一個物件行為取決於它的狀態,並且它必須在執行時刻根據狀態改變它的行為時,就可以考慮使用狀態模式了。

優缺點:

優點

1,狀態模式將與特定狀態相關的行為區域性化,並且將不同狀態的行為分割開來。

2,所有狀態相關的程式碼都存在於某個ConcereteState中,所以通過定義新的子類很容易地增加新的狀態和轉換。

3,狀態模式通過把各種狀態轉移邏輯分不到State的子類之間,來減少相互間的依賴。

缺點

1,狀態模式的使用必然會增加系統類和物件的個數。
2,狀態模式的結構與實現都較為複雜,如果使用不當將導致程式結構和程式碼的混亂。

LCL_data原創於CSDN.NET【http://blog.csdn.net/lcl_data/article/details/10248415】