状态模式

基础介绍

Posted by 邹盛富 on March 28, 2018

使用意图

由于转态导致行为不同,为了方便行为自动适应状态的改变,去掉if或者case语句

结构图

结构图

使用场景

  • 对象收到其他对象的请求时,根据自身的不同状态做出不同的反应
  • 一个操作中含有大量的条件分支语句,并且这些分支依赖于状态

优点

  • 通过增加State的子类可以容易的增加新的状态和转化
  • 状态转换的时候,Context类中只需要重新绑定一个State变量,无须重新赋值,避免内部状态不一致
  • State对象可以被共享
  • 状态不会出错,比较安全

缺点

  • 增加了子类的数目,类之间比较混乱

实现

  • 由谁定义状态的状态的转换:
    • Context类中定义后继状态以及何时进行转换
    • 由State子类定义后继状态以及何时进行转换
  • 创建和销毁State子类对象:
    • 状态在运行时是不可知的并且不经常改变状态时,对象使用时创建不使用时销毁
    • 状态对象含有大量信息且状态变换频繁时,在运行前一次创建所有对象,运行时不销毁,运行结束后销毁
  • Context类中必须含有一个changeState的改变状态的方法供State类方法调用

与其他模式关系

  • State子类通常使用单例模式
  • 与策略模式相比:状态模式相互转换不是用户指定的,而是自动转换,相对安全

示例代码

//  
//  TcpState.h  
//  textD  
//  
//  Created by md101 on 15/10/19.  
//  Copyright © 2015年 md101. All rights reserved.  
//  

#ifndef TcpState_h  
#define TcpState_h  

#include <iostream>  
#include <string>  
class TcpConnection;  
//#include "TcpConnection.h"  
using namespace std;  
class TcpState  
{  
public:  
    TcpState(){  
        cout<<"TcpState初始化"<<endl;  
        cout<<instance<<endl;  
    }  
    virtual ~TcpState(){}  
    /*把子类的所有行为封装到接口中,每个函数都有一个TcpConnection作为参数从而访问TcpConnection中的数据和改变连接的状态*/  
    virtual void transmit(TcpConnection* con,string message){  
        cout<<message<<endl;}  
    virtual void activeOpen(TcpConnection* con){}  
    virtual void passiveOpen(TcpConnection* con){}  
    virtual void close(TcpConnection* con){}  
    virtual void syschronize(TcpConnection* con){}  
    virtual void acknowledge(TcpConnection* con){}  
    virtual void send(TcpConnection* con){}  
    static void release(){ std::cout<<"TcpState"<<endl;}  
protected:  
    /*可有可无,其本质就是调用Context方法改变其状态,可再其方法中实现*/  
    void changeState(TcpConnection* con, TcpState* state);  
    static TcpState* instance;  
};  

#endif /* TcpState_h */  
//  
//  TcpState.cpp  
//  textD  
//  
//  Created by md101 on 15/10/19.  
//  Copyright © 2015年 md101. All rights reserved.  
//  

#include "TcpState.h"  
#include "TcpConnection.h"  

TcpState* TcpState::instance = 0;  
void TcpState::changeState(TcpConnection *con, TcpState *state)  
{  
    con->changeState(state);  
}  

//  
//  TcpListen.h  
//  textD  
//  
//  Created by md101 on 15/10/19.  
//  Copyright © 2015年 md101. All rights reserved.  
//  

#ifndef TcpListen_h  
#define TcpListen_h  

#include <iostream>  
#include "TcpState.h"  

class TcpListen:public TcpState  
{  
public:  
    static TcpListen* getInstace()  
    {  
        if (instance == nullptr) {  
            return new TcpListen;  
        }  
        return dynamic_cast<TcpListen*>(instance);  
    }  

    static void release()  
    {  
        if (instance != nullptr) {  
            delete instance;  
            instance = nullptr;  
        }  
    }  

    virtual void send(TcpConnection *con);  
private:  
    TcpListen(){}  
    TcpListen(const TcpListen& );  
    TcpListen& operator= (const TcpListen&);  
    virtual ~TcpListen(){}  

    //static TcpState* instance;  
};  

#endif /* TcpListen_h */  

//  
//  TcpListen.cpp  
//  textD  
//  
//  Created by md101 on 15/10/19.  
//  Copyright © 2015年 md101. All rights reserved.  
//  

#include "TcpListen.h"  
#include "TcpEstablished.h"  
using namespace std;  
//TcpState* TcpListen::instance = 0;  
void TcpListen::send(TcpConnection *con)  
{  
    cout<<"TcpListen::send"<<endl;  
    changeState(con, TcpEstablished::getInstance());  
}  

//  
//  TcpEstablished.h  
//  textD  
//  
//  Created by md101 on 15/10/19.  
//  Copyright © 2015年 md101. All rights reserved.  
//  

#ifndef TcpEstablished_h  
#define TcpEstablished_h  

#include <iostream>  
#include "TcpState.h"  

class TcpEstablished:public TcpState  
{  
public:  
    /*单例设计模式*/  
    static TcpEstablished* getInstance(){  
        if (instance == nullptr) {  
            return new TcpEstablished;  
        }  
        return dynamic_cast<TcpEstablished*>(instance);  
    }  

    static void release(){  
        if (instance != nullptr) {  
            delete instance;  
            instance = nullptr;  
        }  
    }  

    virtual void transmit(TcpConnection *con, string message);  
    virtual void close(TcpConnection *con);  
private:  
    TcpEstablished(){}  
    virtual ~TcpEstablished(){}  
    TcpEstablished(const TcpEstablished& );  
    TcpEstablished& operator=(const TcpEstablished& );  

    //static TcpState* instance;  
};  

#endif /* TcpEstablished_h */  

//  
//  TcpEstablished.cpp  
//  textD  
//  
//  Created by md101 on 15/10/19.  
//  Copyright © 2015年 md101. All rights reserved.  
//  

#include "TcpEstablished.h"  
#include "TcpListen.h"  

using namespace std;  
//TcpState* TcpEstablished::instance = 0;  
void TcpEstablished::transmit(TcpConnection *con, string message)  
{  
    cout<<"TcpEstablished::transmit"<<message<<endl;  
    changeState(con, TcpListen::getInstace());  

}  

void TcpEstablished::close(TcpConnection *con)  
{  
    cout<<"TcpEstablished::close"<<endl;  
    /*具体定义转换成哪种状态,调用TcpConnection类的changeState统一执行*/  
    changeState(con, TcpListen::getInstace());  
}

//  
//  TcpClosed.h  
//  textD  
//  
//  Created by md101 on 15/10/19.  
//  Copyright © 2015年 md101. All rights reserved.  
//  

#ifndef TcpClosed_h  
#define TcpClosed_h  

#include <iostream>  
#include "TcpState.h"  

class TcpClosed:public TcpState  
{  
public:  
    static TcpClosed* getInstance(){  
        if (instance == nullptr) {  
            return new TcpClosed;  
        }  
        return dynamic_cast<TcpClosed*>(instance);  
    }  

    static void release(){  
        if (instance != nullptr) {  
            delete instance;  
            instance = nullptr;  
        }  
    }  

    virtual void activeOpen(TcpConnection *con);  
    virtual void passiveOpen(TcpConnection* con);  
private:  
    TcpClosed(){}  
    virtual ~TcpClosed(){}  
    TcpClosed(const TcpClosed&);  
    TcpClosed& operator= (const TcpClosed&);  

};  

#endif /* TcpClosed_h */  

//  
//  TcpClosed.cpp  
//  textD  
//  
//  Created by md101 on 15/10/19.  
//  Copyright © 2015年 md101. All rights reserved.  
//  

#include "TcpClosed.h"  
#include "TcpEstablished.h"  
#include "TcpListen.h"  
using namespace std;  

void TcpClosed::activeOpen(TcpConnection *con)  
{  
    cout<<"TcpClosed::activeOpen"<<endl;  
    changeState(con, TcpEstablished::getInstance());  
}  

void TcpClosed::passiveOpen(TcpConnection *con)  
{  
    cout<<"TcpClosed::passiveOpen"<<endl;  
    changeState(con, TcpListen::getInstace());  
}

//  
//  TcpConnection.h  
//  textD  
//  
//  Created by md101 on 15/10/19.  
//  Copyright © 2015年 md101. All rights reserved.  
//  

#ifndef TcpConnection_h  
#define TcpConnection_h  

#include <iostream>  
#include "TcpState.h"  
#include "TcpListen.h"  
#include "TcpEstablished.h"  
#include "TcpClosed.h"  

using namespace std;  

class TcpConnection  
{  
public:  
    TcpConnection(){ state = TcpClosed::getInstance(); }  
    virtual ~TcpConnection(){ /*state->release();*/}  

    void activeOpen(){ state->activeOpen(this); }  
    void passiveOpen(){ state->passiveOpen(this); }  
    void close(){ state->close(this); }  
    void send(){ state->send(this); }  
    void acknowledge(){ state->acknowledge(this); }  
    void synchronize(){ state->syschronize(this); }  
    void transmit(string message){ state->transmit(this, message); }  
private:  
    /*必须要有changeState方法供状态类来调用改变状态*/  
    void changeState(TcpState *state){this->state = state;}  
    friend class TcpState;  
private:  
    TcpState* state;  

};  

#endif /* TcpConnection_h */  

//  
//  TcpConnection.cpp  
//  textD  
//  
//  Created by md101 on 15/10/19.  
//  Copyright © 2015年 md101. All rights reserved.  
//  

#include "TcpConnection.h"  


//  
//  main.cpp  
//  textD  
//  
//  Created by md101 on 15/10/19.  
//  Copyright © 2015年 md101. All rights reserved.  
//  

#include <iostream>  
#include "TcpConnection.h"  

using namespace std;  

int main(int argc, const char * argv[]) {  

    TcpConnection *con = new TcpConnection();  
    con->activeOpen();  
    con->transmit("xgdsgdfsg");  
    con->send();  
    TcpClosed::release();  
    TcpEstablished::release();  
    TcpListen::release();  
    delete con;  

    return 0;  
}