状态变化模式:在组件构建过程中,某些对象的状态经常面临变化,如何对这些变化进行有效的管理?同时又维持高层模块的稳定。状态变化模式为这一问题提供了一种解决方案。

典型模式:状态模式(State)、备忘录模式(Memento)

一、状态模式

1.动机

在软件构建过程中,某些对象的状态如果改变,其行为也会随之而发生改变,比如文档处于只读状态,其支持的行为和读写状态支持的行为就可能完全不同。

2.作用

在运行时根据对象的状态来透明地更改对象的行为,而不会为对象操作和状态转化之间引入紧耦合。

3.定义

允许一个对象在其内部状态发生改变时改变它的行为,从而使对象看起来似乎修改了其行为。

4.代码

//原有代码
enum NetworkState
{
Network_Open,
Network_Close,
Network_Connect,
};
class NetworkProcessor{
NetworkState state;
public:
void Operation1(){
if (state == Network_Open){
//**********
state = Network_Close;
}
else if (state == Network_Close){
//..........
state = Network_Connect;
}
else if (state == Network_Connect){
//$$$$$$$$$$
state = Network_Open;
}
}
public void Operation2(){
if (state == Network_Open){
//**********
state = Network_Connect;
}
else if (state == Network_Close){
//.....
state = Network_Open;
}
else if (state == Network_Connect){
//$$$$$$$$$$
state = Network_Close;
}
}
public void Operation3(){
//**********
}
};
//运用状态模式后代码
class NetworkState{
public:
NetworkState* pNext;
virtual void Operation1()=;
virtual void Operation2()=;
virtual void Operation3()=;
virtual ~NetworkState(){}
};
class OpenState :public NetworkState{
static NetworkState* m_instance;
public:
static NetworkState* getInstance(){
//某个对象任何情况下应该只有一种状态,
//故采用单件模式使状态唯一
if (m_instance == nullptr) {
m_instance = new OpenState();
}
return m_instance;
}
void Operation1(){
//********** open状态下的行为1
pNext = CloseState::getInstance();
}
void Operation2(){
//..........
pNext = ConnectState::getInstance();
}
void Operation3(){
//$$$$$$$$$$
pNext = OpenState::getInstance();
}
};
//关闭状态和连接状态 略写
class CloseState:public NetworkState{ }
class ConnectState:public NetworkState{ } class NetworkProcessor{
NetworkState* pState;
public:
NetworkProcessor(NetworkState* pState){
this->pState = pState;
}
void Operation1(){
//...
pState->Operation1();
pState = pState->pNext;
//...
}
void Operation2(){
//...
pState->Operation2();
pState = pState->pNext;
//...
}
void Operation3(){
//...
pState->Operation3();
pState = pState->pNext;
//...
}
};

5.解析

这是一个表示网络行为的设计。网络对象有三种不同状态,open、close、connect。当网络对象收到其他对象的请求时,它根据自身当前状态做出不同的反应。例如,行为1的请求会让open状态变为close。

在状态模式中,引入了一个称为NetworkState的抽象类来表示网络的连接状态。NetworkState类为各不同操作状态的子类声明了一个公共接口。NetworkState子类实现与特定状态相关的行为。

NetworkProcessor类维护了NetWork连接状态对象,一旦状态改变,NetworkProcessor就会改变它使用的状态对象,所调用的NetWorkState类子类也会随之改变。

6.结构

其中,

1.Context(环境,如NetworkProcessor):定义客户感兴趣的接口;维护一个ConcreteState子类的实例,这个实例定义为当前状态;

2.State(状态,如NetworkState):定义一个接口以封装与Context的特定状态相关的行为;

3.ConcreteState(具体状态子类,如OpenState等):每一个子类实现一个与Context的一个状态相关的行为。

7.总结

1.State模式将所有与一个特定状态相关的行为都放入一个State的子类对象中,在对象状态切换时,切换相应的对象,但同时维持State的接口,这样实现了具体操作与状态转换之间的解耦。

2.为不同的状态引入不同的对象使得状态转换变得更加明确,而且可以保证不会出现状态不一致的情况,因为转换是原子性的——即要么彻底转换过来,要么不转换。

3.如果State对象没有实例实例变量,那么各个上下文可以共享同一个State对象,从而节省对象开销。

二、备忘录模式

1.动机

在软件构建过程中,某些对象的状态在转换过程中,可能由于某种需要,要求程序能够回溯到对象之前某个点时的状态。如果使用一些公有接口来让其他对象得到对象的状态,便会暴露对象的细节实现。

2.作用

既能实现对象状态的良好保存与恢复,但同时又不会因此而破坏对象本身的封装性。

3.定义

在不破坏对象封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。这样以后就可以将该对象恢复到原先保存的状态。

4.代码

//备忘录模式实现
class Memento
{
string state;
//..
public:
Memento(const string & s) : state(s) {}
string getState() const { return state; }
void setState(const string & s) { state = s; }
};
class Originator
{
string state;
//....
public:
Originator() {}
Memento createMomento() {
Memento m(state);
return m;
}
void setMomento(const Memento & m) {
state = m.getState();
}
};
int main()
{
Originator orginator;
//捕获对象状态,存储到备忘录
Memento mem = orginator.createMomento();
//... 改变orginator状态 //从备忘录中恢复
orginator.setMomento(memento);
}

5.解析

考虑一个图形编辑器,它支持图形对象之间的连线,而需要保证能撤销操作。

我们可用备忘录模式解决这一问题。一个备忘录是一个对象,它存储另一个对象在某个瞬间的内部状态,而后者称为备忘录的原发器。当需要设置原发器的检查点时,取消操作机制会向原发器请求一个备忘录。原发器用描述当前状态的信息初始化备忘录。只有原发器可以向备忘录中存取信息,备忘录对其他对象“不可见”。

 6.结构

其中,

1.Memento(备忘录):存储原发器对象的内部状态。原发器对象根据需要决定备忘录存储原发器的哪些内部对象;防止原发器以为的对象访问备忘录。

2.Originator(原发器):原发器创建一个备忘录,用于记录当前时刻它的内部状态;使用备忘录恢复内部状态;

3.Caretaker(负责人,如main函数):负责保存好备忘录,但不能对备忘录的内容进行操作或检查。

7.总结

1.备忘录(Memento)存储原发器(Originator)对象的内部状态,在需要时恢复原发器状态。

2. Memento模式的核心是信息隐藏,即Originator需要向外接隐藏信息,保持其封装性。但同时需要将状态保持到外界(Memento)。

学习记录:《C++设计模式——李建忠主讲》6.“状态变化”模式的更多相关文章

  1. 学习记录:《C++设计模式——李建忠主讲》1.设计模式

    1.学习目标 1)理解松耦合设计思想: 2)掌握面向对象设计原则: 3)掌握重构技法改善设计: 4)掌握GOF核心设计模式: 2.定义 每个设计模式描述了一个在我们周围不断重复发生的问题,以及该问题解 ...

  2. 学习记录:《C++设计模式——李建忠主讲》2.面向对象设计原则

    1.课程内容: 重新认识面向对象:面向对象设计原则: 2.重新认识面向对象 1)理解隔离变化:从宏观层面来看,面向对象的构建方式更能适应软件的变化,将变化所带来的影响减为最小: 2)各司其职:从微观层 ...

  3. 学习记录:《C++设计模式——李建忠主讲》3.“组件协作”模式

    “组件协作”模式:现代软件专业分工之后的第一个结果是“框架与应用程序的划分”,“组件协作”模式通过晚期绑定,来实现框架与应用程序之间的松耦合,是二者之间协作时常用的模式.典型模式:Template M ...

  4. 学习记录:《C++设计模式——李建忠主讲》5.“对象性能”模式

    对象性能模式:面向对象很好地解决了抽象地问题,但是必不可免地要付出一定地代价.对于通常情况来讲,面向对象地成本大都可以忽略不计,但某些情况,面向对象所带来地成本必须谨慎处理. 典型模式:单件模式(Si ...

  5. 学习记录:《C++设计模式——李建忠主讲》4.“单一职责”模式

    单一职责模式:在软件组件的设计中,如果责任划分的不清晰,使用继承得到的结果往往是随着需求的变化,子类急剧膨胀,同时充斥着重复代码,这时候的关键是划清责任. 典型模式:装饰模式(Decorator).桥 ...

  6. 学习记录:《C++设计模式——李建忠主讲》7.“领域规则”模式

    领域规则模式:在特定领域中,某些变化虽然频繁,但可以抽象为某种规则.这时候,结合特定的领域,将问题抽象为语法规则,从而给出该领域下的一般性解决方案. 典型模式:解释器模式(Interpreter). ...

  7. 工厂模式(整理自李建忠<C++设计模式>视频)

    整理自李建忠<C++设计模式>视频 一.导入:"对象创建"模式和工厂模式 工厂模式只是该模式下的一种. 二.举例说明 有这样一个场景:需要在MainForm中设计一个按 ...

  8. UWP学习记录10-设计和UI之控件和模式7

    UWP学习记录10-设计和UI之控件和模式7 1.导航控件 Hub,中心控件,利用它你可以将应用内容整理到不同但又相关的区域或类别中. 中心的各个区域可按首选顺序遍历,并且可用作更具体体验的起始点. ...

  9. UWP学习记录9-设计和UI之控件和模式6

    UWP学习记录9-设计和UI之控件和模式6 1.图形和墨迹 InkCanvas是接收和显示墨迹笔划的控件,是新增的比较复杂的控件,这里先不深入. 而形状(Shape)则是可以显示的各种保留模式图形对象 ...

随机推荐

  1. Chrome 浏览器垃圾回收机制与内存泄漏分析

    Chorme 浏览器中的垃圾回收和内存泄漏 垃圾回收 通常情况下,垃圾数据回收分为手动回收和自动回收两种策略. 手动回收策略,何时分配内存.何时销毁内存都是由代码控制的. 自动回收策略,产生的垃圾数据 ...

  2. 19.Linux进程管理概述

    1.进程基本概述 当我们运行一个程序,那么我们将运行的程序叫进程. PS1: 当程序运行为进程后,系统会为该进程分配内存,以及进程运行的身份和权限. PS2: 在进程运行的过程中,服务器上会有各种状态 ...

  3. Arduino学习笔记⑤ 模拟IO实验

    1.前言     还记得前几个我们都是在讲解数字IO,而其实我们生活中大多数信号都是模拟信号,如声音以及温度变化.在Arduino中,常用0~5v的电压来表示模拟信号. 1.1 模拟输入功能      ...

  4. < Window10更新后VWwareWorkstationPro无法运行(显示更新至新版本) >

    < Window10更新后VWwareWorkstationPro无法运行(显示更新至新版本) > 问题描述 我的Win10在国庆节后更新了微软发布的新补丁,由于当前正在上操作系统课,用到 ...

  5. NVDLA中Winograd卷积的设计

    在AI芯片:高性能卷积计算中的数据复用曾提到,基于变换域的卷积计算--譬如Winograd卷积--并不能适应算法上对卷积计算多变的需求.但Winograd卷积依旧出现在刚刚公开的ARM Ethos-N ...

  6. Springboot 系列(十五)如何编写自己的 Springboot starter

    1. 前言 Springboot 中的自动配置确实方便,减少了我们开发上的复杂性,那么自动配置原理是什么呢?之前我也写过了一篇文章进行了分析. Springboot 系列(三)Spring Boot ...

  7. 回头看 vue-router

    回头看 vue-router 复习 我的github iSAM2016 目录 响应路由参数的变化 嵌套路由 函数式导航 路由的命名 示例:切换路由的时候可以修改页面的标题 导航钩子 全局钩子 实例:检 ...

  8. ThreadPoolExecutor源码中的适配器模式

    什么是适配器模式 网上已有很多的教程,不细讲了.可以参考:五分钟了解设计模式(3)---适配器模式 在适配器模式中,一定要识别清楚,Target Adaptee Adapter分别是哪些类或接口,这样 ...

  9. PHP通过JSON给JS赋值;JS通过JSON给PHP传值

    $fileNames = array(); // 是数组,不是字符串 $filesJSON = json_encode($fileNames);// 转成json格式 var oldFiles = n ...

  10. Kruskal算法求最小生成树 笔记与思路整理

    整理一下前一段时间的最小生成树的算法.(其实是刚弄明白 Kruskal其实算是一种贪心算法.先将边按权值排序,每次选一条没选过的权值最小边加入树,若加入后成环就跳过. 先贴张图做个示例. (可视化均来 ...