生活中的状态模式——水之三态
什么是状态?
状态即事物所处的某一种形态。状态模式是说一个对象在其内部状态发生改变时,其表现的行为和外在属性不一样,这个对象看上去就像是改变了它的类型一样。因此,状态模式又称为对象的行为模式。
如我们生活中经常见到的水,就有三种不同状态冰、水、水蒸汽,三种状态所表现的外在性质完全不一样:1.冰,质坚硬,无流动性,表面光滑;2.水,具有流动性;3.水蒸汽,肉眼看不见,却存在于空气中,质轻。这三种状态特性是不相差巨大?简直就不像是同一种物质的,但事实却是不管它是在什么状态,其特里组成都是一样的,都是水分子(H2O)。
水
以水为例说状态模式
你还记得初中物理学书上的这副图吗?水有三种状态:固、液、气,三种状态表现出不同的特性和行为,它们之间的转换也伴随着一着热力学的现象。现在要用程序来模拟水的三种状态和相互转换,要如何实现呢?
水之三态
我们从对象的角度来考虑会有哪个类,首先不管它是什么状态始终是水(H2O),所以会有一个Water类;而它又有三种状态,我们可以定义三个状态类:SolidState、LiquidState、GaseousState;从SolidState、LiquidState、GaseousState这三个单词中我们会发现都有一个State后缀,于是我们会想它们之间是否有一些共性,能否提取出一个更抽象的类,这个类就是状态类(State)。这些类之间的关系大致如下:
水与状态之间的类图关系
Ok,我们已经知道了大概的关系,那就开始Coding实现吧,在实现的过程中不断完善……
class="prettyprint">class="language-Java hljs cs">Water.h:
class State;
class Water
{
:
();
Water(State* pState, & strName);
~Water();
:
//改变状态
(State* pState);
SetTemperature( nTemperature);
GetTemperature();
RiseTemperature( nStep);
ReduceTemperature( nStep);
GetName();
DoWork();
:
m_nTemperature;
m_strName;
State* m_pState;
};
State.h:
class Water;
class State
{
:
~ () { }
DoWork(Water* pWater) = ;
GetStateName();
:
( & strName) : (strName){}
m_strStateName;
};
class SolidState : State
{
:
SolidState* ();
DoWork(Water* pWater);
:
( & strName) : (strName) { }
SolidState* s_pSolidState;
class CGarbo{
:
~ ()
{
(SolidState::s_pSolidState != NULL)
{
delete SolidState::s_pSolidState;
}
}
};
CGarbo s_Carbo;
};
class LiquidState : State
{
:
LiquidState* ();
DoWork(Water* pWater);
:
( & strName) : (strName) { }
LiquidState* s_pLiquidState;
class CGarbo{
:
~ ()
{
(LiquidState::s_pLiquidState != NULL)
{
delete LiquidState::s_pLiquidState;
}
}
};
CGarbo s_Carbo;
};
class GaseousState : State
{
:
GaseousState* ();
DoWork(Water* pWater);
:
( & strName) : (strName){ }
GaseousState* s_pGaseousState;
class CGarbo{
:
~ ()
{
(GaseousState::s_pGaseousState != NULL)
{
delete GaseousState::s_pGaseousState;
}
}
};
CGarbo s_Carbo;
};
Water.cpp:
Water::Water() : m_pState(NULL), m_strName( )
{
SetTemperature( );
}
Water::Water( State* pState, & strName) : m_nTemperature( ), m_pState(pState), m_strName(strName)
{
(m_pState->GetStateName().compare( ) == )
{
m_nTemperature = - ;
} (m_pState->GetStateName().compare( ) == )
{
m_nTemperature = ;
} (m_pState->GetStateName().compare( ) == )
{
m_nTemperature = ;
}
}
Water::~Water()
{
}
Water::ChangeState( State* pState )
{
(!pState)
{
;
}
(!m_pState)
{
cout << << pState->GetStateName() << endl;
}
{
cout << << m_pState->GetStateName() << << pState->GetStateName() << endl;
}
m_pState = pState;
;
}
Water::SetTemperature( nTemperature )
{
m_nTemperature = nTemperature;
(m_nTemperature <= )
{
ChangeState(SolidState::GetInstance());
} (m_nTemperature > && m_nTemperature <= )
{
ChangeState(LiquidState::GetInstance());
}
{
ChangeState(GaseousState::GetInstance());
}
}
Water::GetTemperature()
{
m_nTemperature;
}
Water::RiseTemperature( nStep )
{
SetTemperature(m_nTemperature + nStep);
}
Water::ReduceTemperature( nStep )
{
SetTemperature(m_nTemperature - nStep);
}
std:: Water::GetName()
{
m_strName;
}
Water::DoWork()
{
(m_pState)
{
m_pState->DoWork( );
}
}
State.cpp:
State::GetStateName()
{
m_strStateName;
}
SolidState* SolidState::s_pSolidState = NULL;
LiquidState* LiquidState::s_pLiquidState = NULL;
GaseousState* GaseousState::s_pGaseousState = NULL;
SolidState* SolidState::GetInstance()
{
(!s_pSolidState)
{
s_pSolidState = SolidState( );
}
s_pSolidState;
}
SolidState::DoWork( Water* pWater )
{
cout << << pWater->GetTemperature() <<
<< << endl;
}
LiquidState* LiquidState::GetInstance()
{
(!s_pLiquidState)
{
s_pLiquidState = LiquidState( );
}
s_pLiquidState;
}
LiquidState::DoWork( Water* pWater )
{
cout << << pWater->GetTemperature() <<
<< << endl;
}
GaseousState* GaseousState::GetInstance()
{
(!s_pGaseousState)
{
s_pGaseousState = GaseousState( );
}
s_pGaseousState;
}
GaseousState::DoWork( Water* pWater )
{
cout << << pWater->GetTemperature() <<
<< << endl;
}
测试代码:
TestStateDesign()
{
Water water;
water.DoWork();
water.SetTemperature(- );
water.DoWork();
water.RiseTemperature( );
water.DoWork();
water.RiseTemperature( );
water.DoWork();
water.ReduceTemperature( );
water.DoWork();
}
结果如下:
初始化为液态
我性格温和,当前体温25摄氏度,我可滋润万物,饮用我可让你活力倍增……
由液态变为固态
我性格高冷,当前体温-4摄氏度,我坚如钢铁,仿如一冷血动物,请用我砸人,嘿嘿……
由固态变为液态
我性格温和,当前体温4摄氏度,我可滋润万物,饮用我可让你活力倍增……
由液态变为气态
我性格热烈,当前体温114摄氏度,飞向天空是我毕生的梦想,在这你将看不到我的存在,
我将达到无我的境界……
由气态变为固态
我性格高冷,当前体温-16摄氏度,我坚如钢铁,仿如一冷血动物,请用我砸人,嘿嘿……
好了,上面的程序已经完美地帮我们完成了水的三种状态及其转变的模拟。我们再来整理一个上面的代码中的类图结构,如下图:
水与状态之间的类图关系
SolidState、LiquidState、GaseousState三个类用了单例的模式,因为状态只需要一个对象就可以了,这三个类中CGarbo是一个内部类,只为了释放静态对象,关于单例模式的用法,可以参考《生活中的单例——不是单身》。Water中的ChangeState可方便地进行三种状态之间的转换。
状态模式总结
通过上面一个生活中的例子,应该很容易能明白状态模式吧!其实也简单,其结构关系如下:
状态模式结构图
Behavior是不同一个对象在不同状态下的行为(如DoWork),ChangeState用于改变对象的状态,Request则是操作请求(如RiseTemperature和)。