状态模式——水之三态

什么是状态?

状态即事物所处的某一种形态。状态模式是说一个对象在其内部状态发生改变时,其表现的行为和外在属性不一样,这个对象看上去就像是改变了它的类型一样。因此,状态模式又称为对象的行为模式。

如我们生活中经常见到的水,就有三种不同状态冰、水、水蒸汽,三种状态所表现的外在性质完全不一样:1.冰,质坚硬,无流动性,表面光滑;2.水,具有流动性;3.水蒸汽,肉眼看不见,却存在于空气中,质轻。这三种状态特性是不相差巨大?简直就不像是同一种物质的,但事实却是不管它是在什么状态,其特里组成都是一样的,都是水分子(H2O)。


以水为例说状态模式

你还记得初中物理学书上的这副图吗?水有三种状态:固、液、气,三种状态表现出不同的特性和行为,它们之间的转换也伴随着一着热力学的现象。现在要用程序来模拟水的三种状态和相互转换,要如何实现呢?

水之三态

我们从对象的角度来考虑会有哪个类,首先不管它是什么状态始终是水(H2O),所以会有一个Water类;而它又有三种状态,我们可以定义三个状态类:SolidState、LiquidState、GaseousState;从SolidState、LiquidState、GaseousState这三个单词中我们会发现都有一个State后缀,于是我们会想它们之间是否有一些共性,能否提取出一个更抽象的类,这个类就是状态类(State)。这些类之间的关系大致如下:

水与状态之间的类图关系

Ok,我们已经知道了大概的关系,那就开始Coding实现吧,在实现的过程中不断完善……

Water.h:

#ifndef __WATER_H__
#define __WATER_H__
//===============================================================
class State;
//===============================================================
class Water
{
public:
    Water();
    Water(State* pState, const string& strName);
    ~Water();
public:
    //改变状态
    bool ChangeState(State* pState);
    //设置温度
    void SetTemperature(int nTemperature);
    //获取温度
    int GetTemperature();
    //升温,nStep升高的幅度
    void RiseTemperature(int nStep);
    //降温,nStep降低的幅度
    void ReduceTemperature(int nStep);
    //获取名称
    string GetName();
    //水的作用(功效)
    void DoWork();
private:
    int         m_nTemperature;         //水温
    string      m_strName;              //名称
    State*      m_pState;               //状态
};
#endif  //__WATER_H__

State.h:

#ifndef __STATE_H__
#define __STATE_H__
//===============================================================
class Water;
//===============================================================
class State
{
public:
    virtual ~State() { }
    //某一状态下表现的行为,用途
    virtual void DoWork(Water* pWater) = 0;
    virtual string GetStateName();
protected:
    State(const string& strName) : m_strStateName(strName){}
    string m_strStateName;
};
class SolidState : public State
{
public:
    static SolidState* GetInstance();
    virtual void DoWork(Water* pWater);
private:
    SolidState(const string& strName) : State(strName) { }
    static SolidState* s_pSolidState;
    class CGarbo{
    public:
        ~CGarbo()
        {
            if (SolidState::s_pSolidState != NULL)
            {
                delete SolidState::s_pSolidState;
            }
        }
    };
    static CGarbo s_Carbo;
};
class LiquidState : public State
{
public:
    static LiquidState* GetInstance();
    virtual void DoWork(Water* pWater);
private:
    LiquidState(const string& strName) : State(strName) { }
    static LiquidState* s_pLiquidState;
    class CGarbo{
    public:
        ~CGarbo()
        {
            if (LiquidState::s_pLiquidState != NULL)
            {
                delete LiquidState::s_pLiquidState;
            }
        }
    };
    static CGarbo s_Carbo;
};
class GaseousState : public State
{
public:
    static GaseousState* GetInstance();
    virtual void DoWork(Water* pWater);
private:
    GaseousState(const string& strName) : State(strName){ }
    static GaseousState* s_pGaseousState;
    class CGarbo{
    public:
        ~CGarbo()
        {
            if (GaseousState::s_pGaseousState != NULL)
            {
                delete GaseousState::s_pGaseousState;
            }
        }
    };
    static CGarbo s_Carbo;
};
#endif  //__STATE_H__

Water.cpp:

#include "stdafx.h"
#include "Water.h"
#include "State.h"
Water::Water() : m_pState(NULL), m_strName("水(H2O)")
{
    SetTemperature(25);
}
Water::Water( State* pState, const string& strName) : m_nTemperature(0), m_pState(pState), m_strName(strName)
{
    if (m_pState->GetStateName().compare("固态") == 0)
    {
        m_nTemperature = -25;
    } else if (m_pState->GetStateName().compare("液态") == 0)
    {
        m_nTemperature = 25;
    } else if (m_pState->GetStateName().compare("气态") == 0)
    {
        m_nTemperature = 125;
    }
}
Water::~Water()
{
}
bool Water::ChangeState( State* pState )
{
    if (!pState)
    {
        return false;
    }
    if (!m_pState)
    {
        cout << "初始化为" << pState->GetStateName() << endl;
    } else
    {
        cout << "由" << m_pState->GetStateName() << "变为" << pState->GetStateName() << endl;
    }
    m_pState = pState;
    return true;
}
void Water::SetTemperature( int nTemperature )
{
    m_nTemperature = nTemperature;
    if (m_nTemperature <= 0)
    {
        ChangeState(SolidState::GetInstance());
    } else if (m_nTemperature > 0 && m_nTemperature <= 100)
    {
        ChangeState(LiquidState::GetInstance());
    } else
    {
        ChangeState(GaseousState::GetInstance());
    }
}
int Water::GetTemperature()
{
    return m_nTemperature;
}
void Water::RiseTemperature( int nStep )
{
    SetTemperature(m_nTemperature + nStep);
}
void Water::ReduceTemperature( int nStep )
{
    SetTemperature(m_nTemperature - nStep);
}
std::string Water::GetName()
{
    return m_strName;
}
void Water::DoWork()
{
    if (m_pState)
    {
        m_pState->DoWork(this);
    }
}

State.cpp:

#include "stdafx.h"
#include "State.h"
#include "Water.h"
string State::GetStateName()
{
    return m_strStateName;
}
//===============================================================
SolidState* SolidState::s_pSolidState = NULL;
LiquidState* LiquidState::s_pLiquidState = NULL;
GaseousState* GaseousState::s_pGaseousState = NULL;
//===============================================================
SolidState* SolidState::GetInstance()
{
    if (!s_pSolidState)
    {
        s_pSolidState = new SolidState("固态");
    }
    return s_pSolidState;
}
void SolidState::DoWork( Water* pWater )
{
    cout << "我性格高冷,当前体温" << pWater->GetTemperature() << "摄氏度,"
    << "我坚如钢铁,仿如一冷血动物,请用我砸人,嘿嘿……" << endl;
}
LiquidState* LiquidState::GetInstance()
{
    if (!s_pLiquidState)
    {
        s_pLiquidState = new LiquidState("液态");
    }
    return s_pLiquidState;
}
void LiquidState::DoWork( Water* pWater )
{
    cout << "我性格温和,当前体温" << pWater->GetTemperature() << "摄氏度,"
    << "我可滋润万物,饮用我可让你活力倍增……" << endl;
}
GaseousState* GaseousState::GetInstance()
{
    if (!s_pGaseousState)
    {
        s_pGaseousState = new GaseousState("气态");
    }
    return s_pGaseousState;
}
void GaseousState::DoWork( Water* pWater )
{
    cout << "我性格热烈,当前体温" << pWater->GetTemperature() << "摄氏度,"
    << "飞向天空是我毕生的梦想,在这你将看不到我的存在,我将达到无我的境界……" << endl;
}

测试代码:

void TestStateDesign()
{
    Water water;
    water.DoWork();
    water.SetTemperature(-4);
    water.DoWork();
    water.RiseTemperature(8);
    water.DoWork();
    water.RiseTemperature(110);
    water.DoWork();
    water.ReduceTemperature(130);
    water.DoWork();
}

结果如下:

初始化为液态

我性格温和,当前体温25摄氏度,我可滋润万物,饮用我可让你活力倍增……

由液态变为固态

我性格高冷,当前体温-4摄氏度,我坚如钢铁,仿如一冷血动物,请用我砸人,嘿嘿……

由固态变为液态

我性格温和,当前体温4摄氏度,我可滋润万物,饮用我可让你活力倍增……

由液态变为气态

我性格热烈,当前体温114摄氏度,飞向天空是我毕生的梦想,在这你将看不到我的存在,

我将达到无我的境界……

由气态变为固态

我性格高冷,当前体温-16摄氏度,我坚如钢铁,仿如一冷血动物,请用我砸人,嘿嘿……

好了,上面的程序已经完美地帮我们完成了水的三种状态及其转变的模拟。我们再来整理一个上面的代码中的类图结构,如下图:

水与状态之间的类图关系

SolidState、LiquidState、GaseousState三个类用了单例的模式,因为状态只需要一个对象就可以了,这三个类中CGarbo是一个内部类,只为了释放静态对象,关于单例模式的用法,可以参考《生活中的单例——不是单身》。Water中的ChangeState可方便地进行三种状态之间的转换。


状态模式总结

通过上面一个生活中的例子,应该很容易能明白状态模式吧!其实也简单,其结构关系如下:

状态模式结构图

Behavior是不同一个对象在不同状态下的行为(如DoWork),ChangeState用于改变对象的状态,Request则是操作请求(如RiseTemperature和ReduceTemperature)。

版权声明:本文为博主原创文章,未经博主允许不得用于任何商业用途,转载请注明出处。

时间: 2024-10-04 20:57:37

状态模式——水之三态的相关文章

js状态模式

状态模式,当一个对象的内在状态改变时允许改变其行为,这个对象看起来是改变了其类. 状态模式主要解决的是当控制一个对象状态转换的条件表达式过于复杂时的情况.把状态的判断逻辑转移到表示不同状态的一系列类当中,可以把复杂的判断逻辑简化. 既然状态者模式是对已有对象的状态进行抽象,则自然就有抽象状态者类和具体状态者类,而原来已有对象需要保存抽象状态者类的引用,通过调用抽象状态者的行为来改变已有对象的行为.经过上面的分析,状态者模式的结构图也就很容易理解了,具体结构图如下图示. 从上图可知,状态者模式涉及

大话设计模式读书笔记--12.状态模式

定义 状态模式定义: 当一个对象的内在状态改变时,允许改变其行为,这个对象看起来改变了其类 消除庞大的条件分支,将特定状态的行为放入一个对象中 生活中:开灯和关灯是两个状态 模式结构 Context: 上下文环境,维护一个状态实例,定义当前的状态 State: 抽象状态类,定义一个接口,封装与Context的一个特定状态相关的行为 ConcreteState:具体状态.实现Context的一个特定状态相关的行为 代码实现 场景: 12店之前是休闲状态, 之后是忙碌状态 点击下载代码 特点及使用场

设计模式整理_状态模式

状态模式允许对象在内部状态改变的时候,改变它的行为,对象看起来好像修改了它的类.因为这个模式将状态封装成为独立的类,并将动作委托到代表当前状态的对象,而行为会随着内部状态而改变. 在状态模式中,Context内部持有状态,State接口定义了一个所有具体状态的共同接口,任何状态都实现这个相同的接口,这样一来,各个状态可以互相替换.具体状态实现状态接口,所以当Context改变状态的时候,行为也跟着改变.而不管在什么时候,只要有人调用Context的具体方法,它就会用来委托状态处理,下面用具体事例

大量逻辑判断优化的思路——责任链模式复习总结及其和状态模式对比

俗话说,自己写的代码,6个月后也是别人的代码……复习!复习!复习!涉及的总结知识点如下: 责任链模式概念和例子 使用的条件 和状态模式的比较分析 责任链的优缺点 纯的责任链和不纯的责任链 javax.servlet.Filter#doFilter()方法源码分析 基于AOP思想,模拟一个拦截器 前面说了一个状态模式,总结过程中发现和这个责任链的使用场景很类似,都是为了解耦大量复杂业务逻辑判断的,那么他们有什么不同呢?回忆状态模式——状态模式允许通过改变对象的内部状态而改变对象自身的行为,这个对象

第十六章 状态模式

好处:将与特定状态相关的行为局部化,并将不同状态的行为分割开来. 当一个对象的行为取决于它的状态,并且它必须在运行时刻根据状态改变它的行为时,就可以考虑使用状态模式. /** * Created by hero on 16-4-4. */ public abstract class State { public abstract void handle(Context context); } /** * Created by hero on 16-4-4. */ public class Con

23状态模式

 1状态模式的核心内容是: A:状态类 B:工作类 2状态模式的作用:通过状态值自动跳转到要执行的类. 3状态模式具体描述 状态模式:状态模式允许一个对象在其内部状态改变的时候改变行为. 这个对象看上去象是改变了它的类一样.状态模式把所研究的对象的行 为包装在不同的状态对象里,每一个状态对象都属于一个抽象状态类的 一个子类.状态模式的意图是让一个对象在其内部状态改变的时候, 其行为也随之改变.状态模式需要对每一个系统可能取得的状态创立一个状态类的 子类.当系统的状态变化时,系统便改变所选的子

学习日记之状态模式和Effective C++

状态模式(State):当一个对象内在状态改变时,允许改变其行为,这个对象看起来像是改变了其类. (1),状态模式主要负责解决的是当控制一个对象转换的条件表达式过于复杂时的情况.把状态的判断逻辑转移到表示不同状态的一系列类中,可以把复杂的判断逻辑简化. (2),状态模式的好处是将与特定状态相关的行为局部化,并且将不同状态的行为分割开来. (3),将特定的状态相关的行为都放入一个对象中,由于所有与状态相关的代码都存在于某个ConcreteState中,所以通过定义新的子类可以很容易地增加新的状态和

Java设计模式(十) 备忘录模式 状态模式

(十九)备忘录模式 备忘录模式目的是保存一个对象的某个状态,在适当的时候恢复这个对象. class Memento{ private String value; public Memento(String value){ this.value = value; } public String getValue() { return value; } public void setValue(String value) { this.value = value; } } class Storage

State状态模式(C++实现)

状态模式:状态模式的意图是,允许一个对象在其内部状态改变时,改变它的行为.看起来就像是改变了它的类一样. 主要解决的是当控制一个对象状态转换的条件表达式过于复杂时的情况.把状态的判断逻辑转移到表示不同的一系列类当中,可以把复杂的逻辑判断简单化. 类图如下图所示 State类,抽象状态类,定义一个接口以封装与Context的一个特定状态相关的行为.ConcreteState类,具体状态,每一个子类实现一个与Context的一个状态相关的行为.Context类,维护一个ConcreteState子类