设计模式--状态与策略模式

1、来由

  • 最近要把与PC间的通信由原来的自定义的Message改为MQTT的通信方式,QMQTT也有一个数据结构是Message,所以要涉及到把自定义的Message转换为MQTT的Message的需求。每一个自定义Message的转换都不相同,所以想到了可以使用策略模式来处理,一直以来对于策略模式与状态模式都不是很了解,最近的一次是在看《重构》时的第一个例子时作者用到了策略模式,所以想把这两个模式再理一次。

2、Message的转换策略

  • 策略模式是围绕可以互换的算法来创建业务的,对于每一个自定义Message的转换算法都相互独立的。每一个Message 都代表着一个功能,所以有id号,而对于每一种转换,都可以有一个转换的类,id号与转换类形成了一一对应的关系。

###2.1 UML图:

这里写图片描述

2.2 策略类实现

//策略基类
class CMsgConvert
{
public:
	CMsgConvert(int id);
	virtual QMQTT::Message doconvert(const Message&) = 0;
};

//Message A 的转换类
class CMsgAConvert :public CMsgConvert
{
public:
	CMsgAConvert (int id);
	virtual QMQTT::Message doconvert(const Message&);
};

//Message B 的转换类
class CMsgBConvert :public CMsgConvert
{
public:
	CMsgBConvert (int id);
	virtual QMQTT::Message doconvert(const Message&);
};
.
.
.
.
这里我们可以定义更多的转换策略子类

2.3 context 类实现

在我们的策略上下文类中使用一个map将自定义的Message的ID号与转换的子类形成一个映射。

class Context
{
public:
	Context();
	QMQTT::Message doconvert(const Message&);
private:
map<int,CMsgConvert*> mapConvert;

}; 
Context::Context()
{
	//对MAP进行初始化
	mapConvert.set(key,value);
}
QMQTT::Message Context::doconvert(const Message& msg)
{
	//转换
	if(mapConvert.contant(msg.id))
	{
		return mapConvert[msg.id].doconvert(msg);
	}
}

3、策略模式总结

策略模式相来说比较容易理解。

3.1 优点

  1. 策略模式是对算法的封装,它把算法的责任和算法本身分割开,委派给不同的对象管理。策略模式通常把一个系列的算法封装到一系列的策略类里面,作为一个抽象策略类的子类。用一句话来说,就是“准备一组算法,并将每一个算法封装起来,使得它们可以互换”。
  2. 在策略模式中,应当由客户端自己决定在什么情况下使用什么具体策略角色。
  3. 使用策略模式可以避免使用 if…else 和swtich…case
  4. 策略模式提供了对“开闭原则”的完美支持,用户可以在不修改原有系统的基础上选择算法或行为,也可以灵活地增加新的算法或行为。

3.2 缺点

  1. 客户端必须知道所有的策略类,并自行决定使用哪一个策略类。
  2. 策略模式将造成产生很多策略类。
    ###3.3 应用场合
  3. 如果在一个系统里面有许多类,它们之间的区别仅在于它们的行为,那么使用策略模式可以动态地让一个对象在许多行为中选择一种行为。
  4. 一个系统需要动态地在几种算法中选择一种。
  5. 如果一个对象有很多的行为,如果不用恰当的模式,这些行为就只好使用多重的条件选择语句来实现。
  6. 不希望客户端知道复杂的、与算法相关的数据结构,在具体策略类中封装算法和相关的数据结构,提高算法的保密性与安全性。

4、双胞胎兄弟— 状态模式

  • 策略模式与状态模式是双胞胎,在出生的时候才分开,状态模式是通过改变内部的状态来帮助对象控制自已的行为的。
  • 网上有很多的文章在说状态模式与策略模式的区别,也很乱,以我的理解:
    状态模式强调的自己的状态的改变,而这种改变不是用户来改变的,决定权不在context类(策略模式是由context 类开决定的),而在于业务的本身。

或者说:这种状态改变可以用状态机来描述

4.1、UML图

这里写图片描述

在state类里拥有context 的引用,可以在handle的接口内调用context的changeState方法来更新状态。

4.2 Head First 例子----万能糖果机

状态转移图
这里写图片描述

4.3 C++ 代码

4.3.1状态基类:
enum
{
    EGumMachineState_NoQuarter,
    EGumMachineState_HasQuarter,
    EGumMachineState_Sold,
    EGumMachineState_SoldOut,
    EGumMachineState_Winner,

    EGumMachineState_Total,
};//枚举所有状态

class State
{
public:
    State(GumballMachine *p);
    virtual ~State(void){}
public:
    virtual void insertQuarter(void)=0;
    virtual void ejectQuarter(void)=0;
    virtual void turnCrank(void)=0;
    virtual void dispense(void)=0;
protected:
    GumballMachine *pMachine;
};
---------------------------cpp--------------------------------
State::State(GumballMachine *p)
    :pMachine(p)
{

}
4.3.2 无25美分的状态类
class NoQuarterState :public State
{
public:
    NoQuarterState (GumballMachine *p);
    ~NoQuarterState (void){}
public:
    virtual void insertQuarter(void);
    virtual void ejectQuarter(void);
    virtual void turnCrank(void);
    virtual void dispense(void);
};
/******************************cpp***************************/
NoQuarterState ::NoQuarterState (GumballMachine *p)
    :State(p)
{

}

void NoQuarterState::insertQuarter()
{
    qDebug()<<"You inserted a quarter"<<endl;
    pMachine->setState(pMachine->getState(EGumMachineState_HasQuarter));
}

void NoQuarterState::ejectQuarter()
{
    qDebug()<<"You haven't inserted a quarter"<<endl;
}

void NoQuarterState::turnCrank()
{
    qDebug()<<"You turned, but there's no quarter"<<endl;
}

void NoQuarterState::dispense()
{
    qDebug()<<"You need to pay first"<<endl;
}
4.3.3 有25美分的状态类
class HasQuarterState  :public State
{
public:
    HasQuarterState  (GumballMachine *p);
    ~HasQuarterState  (void){}
public:
    virtual void insertQuarter(void);
    virtual void ejectQuarter(void);
    virtual void turnCrank(void);
    virtual void dispense(void);
};
/******************************cpp***************************/
HasQuarterState  ::HasQuarterState  (GumballMachine *p)
    :State(p)
{

}

void HasQuarterState ::insertQuarter()
{
    qDebug()<<"You can't insert another quarter"<<endl;
}

void HasQuarterState ::ejectQuarter()
{
    qDebug()<<"Quarter returned"<<endl;
    pMachine->setState(pMachine->getState(EGumMachineState_NoQuarter));
}

void HasQuarterState ::turnCrank()
{
    qDebug()<<"You turned..."<<endl;

    int winner = rand()%10; // 产生随机数
    qDebug()<<winner<<endl;
    if((winner == 3) && (pMachine->getCount()>1))
    {
        pMachine->setState(pMachine->getState(EGumMachineState_Winner));
    }
    else
    {
        pMachine->setState(pMachine->getState(EGumMachineState_Sold));
    }
}

void HasQuarterState ::dispense()
{
    qDebug()<<"No gumball dispensed"<<endl;
} 
4.3.4 售出糖果状态
class SoldState   :public State
{
public:
    SoldState   (GumballMachine *p);
    ~SoldState   (void){}
public:
    virtual void insertQuarter(void);
    virtual void ejectQuarter(void);
    virtual void turnCrank(void);
    virtual void dispense(void);
};
/******************************cpp***************************/
SoldState::SoldState(GumballMachine *p)
    :State(p)
{

}

void SoldState::insertQuarter()
{
    qDebug()<<"Please wait, we're already giving you a gumball"<<endl;
}

void SoldState  ::ejectQuarter()
{
   qDebug()<<"Sorry, you already turned the Crank"<<endl;
}

void SoldState::turnCrank()
{
    qDebug()<<"Turning twice doesn't get you another gumball!"<<endl;
}

void SoldState::dispense()
{
    pMachine->releaseGumball();
    if(pMachine->getCount()>0)
    {
        pMachine->setState(pMachine->getState(EGumMachineState_NoQuarter));
    }
    else
    {
        qDebug()<<"Oops, out of gumballs!"<<endl;
        pMachine->setState(pMachine->getState(EGumMachineState_SoldOut));
    }
} 
4.3.5 售罄状态
class SoldOutState    :public State
{
public:
    SoldOutState    (GumballMachine *p);
    ~SoldOutState    (void){}
public:
    virtual void insertQuarter(void);
    virtual void ejectQuarter(void);
    virtual void turnCrank(void);
    virtual void dispense(void);
};
/******************************cpp***************************/
SoldOutState ::SoldOutState (GumballMachine *p)
    :State(p)
{

}

void SoldOutState::insertQuarter()
{
    qDebug()<<"You can't insert a quarter, the machine is sold out"<<endl;
}

void SoldOutState::ejectQuarter()
{
    qDebug()<<"You can't eject, you haven't inserted a quarter yet"<<endl;
}

void SoldOutState::turnCrank()
{
    qDebug()<<"You turned, but there are no gumballs"<<endl;
}

void SoldOutState::dispense()
{
    qDebug()<<"No gumball dispensed"<<endl;
} 

4.3.6 赢家状态
class WinnerState:public State
{
public:
    WinnerState(GumballMachine *p);
    ~WinnerState(void){}
public:
    virtual void insertQuarter(void);
    virtual void ejectQuarter(void);
    virtual void turnCrank(void);
    virtual void dispense(void);
};
/******************************cpp***************************/
WinnerState::WinnerState (GumballMachine *p)
    :State(p)
{

}

void WinnerState::insertQuarter()
{
    qDebug()<<"Please wait, we're already giving you a gumball"<<endl;
}

void WinnerState::ejectQuarter()
{
    qDebug()<<"Sorry, you already turned the Crank"<<endl;
}

void WinnerState::turnCrank()
{
    qDebug()<<"Turning twice doesn't get you another gumball!"<<endl;
}

void WinnerState::dispense()
{
    qDebug()<<"You're a Winner! You get two gumballs for your quarter";
    pMachine->releaseGumball();
    if(pMachine->getCount() == 0)
    {
       pMachine->setState(pMachine->getState(EGumMachineState_SoldOut));
    }
    else
    {
       pMachine->releaseGumball();
       if(pMachine->getCount()>0)
       {
           pMachine->setState(pMachine->getState(EGumMachineState_NoQuarter));
       }
       else
       {
           qDebug()<<"Oops, out of gumballs!"<<endl;
           pMachine->setState(pMachine->getState(EGumMachineState_SoldOut));
       }
    }
}
 
4.3.7 Gum Machine
class State;
class GumballMachine
{
public:
    GumballMachine(int numberGumballs=0);
    ~GumballMachine(void);
public:
    // 投入25美分
    void insertQuarter(void);
    // 退回25美分
    void ejectQuarter(void);
    // 转动曲柄
    void turnCrank(void);
public:
    void releaseGumball(void);
    void setState(State* pState);
    int getCount(void);
    State *getState(int);
private:
    int iCount;
    State* pCurState;
    QVector<State*> vecState;
};
/******************************cpp***************************/
GumballMachine::GumballMachine(int numberGumballs)
    :iCount(numberGumballs)
{
    vecState.resize(EGumMachineState_Total);
    vecState[EGumMachineState_NoQuarter] =  new NoQuarterState(this);
    vecState[EGumMachineState_HasQuarter] = new HasQuarterState(this);
    vecState[EGumMachineState_Sold] =       new SoldState(this);
    vecState[EGumMachineState_SoldOut] =    new SoldOutState(this);
    vecState[EGumMachineState_Winner] =     new WinnerState(this);

    pCurState = vecState[EGumMachineState_SoldOut];
    if(numberGumballs>0)
    {
       pCurState = vecState[EGumMachineState_NoQuarter];
    }
}

GumballMachine::~GumballMachine()
{
    for(int i = 0 ; i < EGumMachineState_SoldOut;i++)
    {
      State *state = vecState[i];
      delete state;
    }
}

void GumballMachine::insertQuarter()
{
    pCurState->insertQuarter();
}

void GumballMachine::ejectQuarter()
{
    pCurState->ejectQuarter();
}

void GumballMachine::turnCrank()
{
    pCurState->turnCrank();
    pCurState->dispense();
}

void GumballMachine::releaseGumball()
{
    if(iCount)
    {
        iCount--;
    }
}

void GumballMachine::setState(State *pState)
{
    pCurState = pState;
}

int GumballMachine::getCount()
{
    return iCount;
}

State *GumballMachine::getState(int index)
{
    return vecState[index];
}

4.3.8 Client
    GumballMachine *pGumballMachine = new GumballMachine(5);
    pGumballMachine->insertQuarter();
//    pGumballMachine->ejectQuarter();
    pGumballMachine->turnCrank();
    qDebug()<<"the gumball count is:"<<pGumballMachine->getCount()<<endl;

5、资料

https://en.wikibooks.org/wiki/C%2B%2B_Programming/Code/Design_Patterns#State
http://www.oodesign.com/strategy-pattern.html
http://blog.csdn.net/turkeyzhou/article/details/2792840
http://blog.csdn.net/hguisu/article/details/7558249/
http://blog.csdn.net/u010191243/article/details/45395787
http://design-patterns.readthedocs.io/zh_CN/latest/behavioral_patterns/state.html
http://blog.csdn.net/ccf19881030/article/details/8257659
http://www.cnblogs.com/Mainz/archive/2007/12/15/996081.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
目 录 序言 前言 读者指南 第 1 章 引言 1 1.1 什么是设计模式 2 1.2 Smalltalk MVC 中的设计模式 3 1.3 描述设计模式 4 1.4 设计模式的编目 5 1.5 组织编目 7 1.6 设计模式怎样解决设计问题 8 1.6.1 寻找合适的对象 8 1.6.2 决定对象的粒度 9 1.6.3 指定对象接口 9 1.6.4 描述对象的实现 10 1.6.5 运用复用机制 13 1.6.6 关联运行时刻和编译时刻的结构 15 1.6.7 设计应支持变化 16 1.7 怎样选择设计模式 19 1.8 怎样使用设计模式 20 第 2 章 实例研究:设计一个文档编辑器 22 2.1 设计问题 23 2.2 文档结构 23 2.2.1 递归组合 24 2.2.2 图元 25 2.2.3 组合模式 272.3 格式化 27 2.3.1 封装格式化算法 27 2.3.2 Compositor 和 Composition 27 2.3.3 策略模式 29 2.4 修饰用户界面 29 2.4.1 透明围栏 29 2.4.2 Monoglyph 30 2.4.3 Decorator 模式 32 2.5 支持多种视感标准 32 2.5.1 对象创建的抽象 32 2.5.2 工厂类和产品类 33 2.5.3 Abstract Factory 模式 35 2.6 支持多种窗口系统 35 2.6.1 我们是否可以使用 Abstract Factory 模式 35 2.6.2 封装实现依赖关系 35 2.6.3 Window 和 WindowImp 37 2.6.4 Bridge 模式 40 2.7 用户操作 40 2.7.1 封装一个请求 41 2.7.2 Command 类及其子类 41 2.7.3 撤消和重做 42 2.7.4 命令历史记录 42 2.7.5 Command 模式 44 2.8 拼写检查和断字处理 44 2.8.1 访问分散的信息 44 2.8.2 封装访问和遍历 45 2.8.3 Iterator 类及其子类 46 2.8.4 Iterator 模式 48 2.8.5 遍历和遍历过程中的动作 48 2.8.6 封装分析 48 2.8.7 Visitor 类及其子类 51 2.8.8 Visitor 模式 52 2.9 小结 53 第 3 章 创建型模式 54 3.1 Abstract Factory(抽象工厂)—对象创建型模式 57 3.2 Builder(生成器)—对象创建型模式 633.3 Factory Method(工厂方法)—对象创建型模式 70 3.4 Prototype(原型)—对象创建型模式 87 3.5 Singleton(单件)—对象创建型模式 84 3.6 创建型模式的讨论 89 第 4 章 结构型模式 91 4.1 Adapter(适配器)—类对象结构型模式 92 4.2 Bridge(桥接)—对象结构型模式 100 4.3 Composite(组成)—对象结构型模式 107 4.4 Decorator(装饰)—对象结构型模式 115 4.5 FACADE(外观)—对象结构型模式 121 4.6 Flyweight(享元)—对象结构型模式 128 4.7 Proxy(代理)—对象结构型模式 137 4.8 结构型模式的讨论 144 4.8.1 Adapter 与 Bridge 144 4.8.2 Composite、 Decorator 与 Proxy 145 第 5 章 行为模式 147 5.1 CHAIN OF RESPONSIBIL ITY(职责链)—对象行为型模式 147 5.2 COMMAND(命令)—对象行为型模式 154 5.3 INTERPRETER(解释器)—类行为型模式 162 5.4 ITERATOR(迭代器)—对象行为型模式 171 5.5 MEDIATOR(中介者)—对象行为型模式 181 5.6 MEMENTO(备忘录)—对象行为型模式 188 5.7 OBSERVER(观察者)—对象行为型模式 194 5.8 STATE(状态)—对象行为型模式 201 5.9 STRATEGY(策略)—对象行为型模式 208 5.10 TEMPLATE METHOD(模板方法)—类行为型模式 214 5.11 VISITOR(访问者)—对象行为型模式 218 5.12 行为模式的讨论 228 5.12 1 封装变化 228 5.12.2 对象作为参数 228 5.12.3 通信应该被封装还是被分布 229 5.12.4 对发送者和接收者解耦 229 5.12.5 总结 231 第 6 章 结论 232 6.1 设计模式将带来什么 2326.2 一套通用的设计词汇 23
Java设计模式是一组经过实践验证的面向对象设计原则和模式,可以帮助开发人员解决常见的软件设计问题。下面是常见的23种设计模式: 1. 创建型模式(Creational Patterns): - 工厂方法模式(Factory Method Pattern) - 抽象工厂模式(Abstract Factory Pattern) - 单例模式(Singleton Pattern) - 原型模式(Prototype Pattern) - 建造者模式(Builder Pattern) 2. 结构型模式(Structural Patterns): - 适配器模式(Adapter Pattern) - 桥接模式(Bridge Pattern) - 组合模式(Composite Pattern) - 装饰器模式(Decorator Pattern) - 外观模式(Facade Pattern) - 享元模式(Flyweight Pattern) - 代理模式(Proxy Pattern) 3. 行为型模式(Behavioral Patterns): - 责任链模式(Chain of Responsibility Pattern) - 命令模式(Command Pattern) - 解释器模式(Interpreter Pattern) - 迭代器模式(Iterator Pattern) - 中介者模式(Mediator Pattern) - 备忘录模式(Memento Pattern) - 观察者模式(Observer Pattern) - 状态模式(State Pattern) - 策略模式(Strategy Pattern) - 模板方法模式(Template Method Pattern) - 访问者模式(Visitor Pattern) 4. 并发型模式(Concurrency Patterns): - 保护性暂停模式(Guarded Suspension Pattern) - 生产者-消费者模式(Producer-Consumer Pattern) - 读写锁模式(Read-Write Lock Pattern) - 信号量模式(Semaphore Pattern) - 线程池模式(Thread Pool Pattern) 这些设计模式可以根据问题的特点和需求来选择使用,它们提供了一些可复用的解决方案,有助于开发高质量、可维护且易于扩展的软件系统。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值