面向对象程序设计第七次实验课——状态模式
来源:互联网 发布:ae渲染快捷键 mac 编辑:程序博客网 时间:2024/06/04 19:33
题目要求是自己开脑洞想一个状态模式的例子,实现之。
例子详见后文。
状态模式简介:
http://www.cnblogs.com/wangjq/archive/2012/07/16/2593485.html
State.h
#pragma once#include "Person.h"class Person;class State{ public: State() = default; ~State() = default; virtual void study(Person *per) = 0; virtual void play(Person *per) = 0; virtual void eat(Person *per) = 0; virtual void exam(Person *per) = 0; void sleep(Person *per);};
State.cpp
#include "State.h"#include "Person.h"#include <iostream>using namespace std;void State::sleep(Person *per){ cout << "Sound Sleep ~" << endl; cout << "a new day is coming ~" << endl; per -> setstate(per -> getNewState()); return ;}
Exciting.h
#pragma once#include "State.h"class Exciting : public State{ public: Exciting() = default; ~Exciting() = default; virtual void study(Person *per) override; virtual void play(Person *per) override; virtual void eat(Person *per) override; virtual void exam(Person *per) override;};
Exciting.cpp
#include <iostream>#include "Exciting.h"#include "Person.h"#include "Happy.h"#include "Sad.h"#include "Soso.h"using namespace std;void Exciting::study(Person *per){ cout << "Excited! Study!" << endl; cout << "Gain lots of knowledge! You're content with yourself~" << endl; per -> setstate(new Happy); cout << "Get into Happy Mode ~" << endl; return ;}void Exciting::play(Person *per){ cout << "Excited! Play!" << endl; cout << "You win a lot!" << endl; cout << "Still Exciting!" << endl;}void Exciting::eat(Person *per){ cout << "Excited! Eat!" << endl; cout << "You eat too much!" << endl; per -> setstate(new Soso); cout << "Get into Soso Mode" << endl;}void Exciting::exam(Person *per){ cout << "Excited! Exam!" << endl; cout << "Too Excited to take an exam!" << endl; cout << "You fail the exam!" << endl; per ->setstate(new Sad); cout << "Get into Sad Mode 555~" << endl;}
Happy.h
#pragma once#include "State.h"class Happy : public State{ public: Happy() = default; ~Happy() = default; virtual void study(Person *per) override; virtual void play(Person *per) override; virtual void eat(Person *per) override; virtual void exam(Person *per) override;};
Happy.cpp
#include "Happy.h"#include "Exciting.h"#include "Person.h"#include "Happy.h"#include "Sad.h"#include "Soso.h"#include <iostream>using namespace std;void Happy::study(Person *per){ cout << "Happy~ Study~" << endl; cout << "Gain lots of knowledge~ You're proud of yourself!" << endl; per -> setstate(new Exciting); cout << "Get into Excited Mode !" << endl; return ;}void Happy::play(Person *per){ cout << "Happy~ Play!" << endl; cout << "You win a lot!" << endl; per -> setstate(new Exciting); cout << "Get into Excited Mode !" << endl;}void Happy::eat(Person *per){ cout << "Happy~ Eat~" << endl; cout << "You eat well!" << endl; cout << "Still Happy~" << endl;}void Happy::exam(Person *per){ cout << "Happy~ Exam..." << endl; cout << "An hard exam... You do just soso" << endl; per ->setstate(new Soso); cout << "Get into SoSo Mode" << endl;}
Soso.h
#pragma once#include "State.h"class Soso : public State{ public: Soso() = default; ~Soso() = default; virtual void study(Person *per) override; virtual void play(Person *per) override; virtual void eat(Person *per) override; virtual void exam(Person *per) override;};
Soso.cpp
#include "Soso.h"#include "Person.h"#include "Sad.h"#include "Happy.h"#include "Exciting.h"#include <iostream>using namespace std;void Soso::study(Person *per){ cout << "Soso... Study..." << endl; cout << "Hard to understand... You're tired..." << endl; per -> setstate(new Sad); cout << "Get into Sad Mode 555~" << endl; return ;}void Soso::play(Person *per){ cout << "Soso... Play!" << endl; cout << "You win some games~" << endl; per -> setstate(new Happy); cout << "Get into Happy Mode ~" << endl;}void Soso::eat(Person *per){ cout << "Soso... Eat~" << endl; cout << "You eat well~" << endl; per -> setstate(new Happy); cout << "Get into Happy Mode ~" << endl;}void Soso::exam(Person *per){ cout << "Soso... Exam..." << endl; cout << "An hard exam... You do not well 555~" << endl; per ->setstate(new Sad); cout << "Get into Sad Mode 555~" << endl;}
Sad.h
#pragma once#include "State.h"class Sad: public State{ public: Sad() = default; ~Sad() = default; virtual void study(Person *per) override; virtual void play(Person *per) override; virtual void eat(Person *per) override; virtual void exam(Person *per) override;};
Sad.cpp
#include "Person.h"#include "Sad.h"#include "Soso.h"#include "Happy.h"#include "Exciting.h"#include <iostream>using namespace std;void Sad::study(Person *per){ cout << "Sad 555~ Study~" << endl; cout << "You forget the reason why you're Sad~" << endl; per -> setstate(new Happy); cout << "Get into Happy Mode ~" << endl; return ;}void Sad::play(Person *per){ cout << "Sad 555~ Play!" << endl; cout << "You win some games~" << endl; per -> setstate(new Happy); cout << "Get into soso Mode ..." << endl;}void Sad::eat(Person *per){ cout << "Sad 555~ Eat~" << endl; cout << "You eat well~" << endl; per -> setstate(new Soso); cout << "Get into soso Mode ~" << endl;}void Sad::exam(Person *per){ cout << "Sad 555~ Exam 555~" << endl; cout << "An hard exam... You do bad 555~" << endl; cout << "You're extremely Sad 55555~" << endl;}
Person.h
#pragma once#include "State.h"class State;class Person{ public: Person(void); Person(State *state); ~Person() = default; void study(void); void play(void); void eat(void); void exam(void); void sleep(void); const State* getstate(void); void setstate(State *state); State* getNewState(void); private: State *m_state;};
Person.cpp
#include "Person.h"#include "Happy.h"#include "Exciting.h"#include "Soso.h"#include "Sad.h"#include <iostream>using namespace std;Person::Person(State *state) : m_state(state) {}const State* Person::getstate(void){ return m_state;}void Person::setstate(State *state){ m_state = state;}State* Person::getNewState(void) { cout << "choose your new state:" << endl; cout << "1. Happy" << endl; cout << "2. Excited" << endl; cout << "3. So So" << endl; cout << "4. Sad" << endl; int state, flag = 1; while (flag) { cin >> state; switch (state) { case 1: return new Happy; break; case 2: return new Exciting; break; case 3: return new Soso; break; case 4: return new Sad; break; default: ; } }}void Person::eat(void) { m_state -> eat(this); return ;}void Person::exam(void){ m_state -> exam(this); return;}void Person::study(void){ m_state -> study(this); return ;}void Person::play(void){ m_state -> play(this); return ;}void Person::sleep(void){ m_state -> sleep(this);}
main.cpp
#include <iostream>#include "Group.h"#include "Decorator.h"#include "Life.h"#include "Business.h"#include "Study.h"#include <vector>using namespace std;int main(int argc, char** argv) { Person per("Jason", "12345"); vector<Person *> vper; vper.push_back(&per); Group *p1 = new Group(vper); Group *p2 = new Life(*p1); Group *p3 = new Study(*p2); Group *p4 = new Business(*p3); per.sendMessage("hello!", *p4); cout << endl; per.sendMessage("hi!", *p2); cout << endl; per.getMessageRecord(*p1); cout << endl; per.getMessageRecord(*p4); cout << endl; return 0;}
第七次实验报告
一、 场景描述
首先说一下自己对于状态模式的理解。一个对象可能会在不同的时间不同的地点不同的情况会有不同的状态,而对应于不同的状态,这个对象的部分行为会有所改变,这就是状态模式出现的原因。我认为状态模式是用于解决一个这样一个情形:对象会有较多的状态,同时又有相当一部分行为会因为状态的改变而改变。
状态模式的基本模型是这样的,有一个具体的类描述一种事务,充当用户接口,并持有一个State类的指针。State类是一个抽象类,是所有具体状态的父类,它拥有关联类基于状态的行为的实现,规定了所有子类应该定义的行为。每一个具体的状态类依据状态定义行为。
我的程序描述了这样一个场景。有一个人(Person),他有五种行为(study、eat、play、exam、sleep),有四种心情(状态:happy、excited、so-so、sad),在不同的心情下,这个人做同一件事情会有不同的结果,相应的会有状态的变化。当一天结束,一个人sleep后可以选择新的一天以什么状态开始。
Person类中拥有一个State类型的指针m_state,动态类型是State的子类之一,在执行行为的时候,调用m_state指向对象的行为,行为过后,Person中m_state的动态类型可能改变。
二、 多态
为什么要多态呢?注意,状态模式要求对于不同的状态,对象的行为会发生改变。显然,这个状态并不是编译时确定的,而是运行时才能确定的,这符合多态的定义。因此,多态可以解决这一问题,只要把不同的状态抽象成不同的类,并使用一个相同的祖先类管理这些类,就可以用多态的思想解决问题。
三、不使用多态
我们当然可以用面向过程和基于对象的思想解决这一问题。我想到了两种方法。
(1)使用分支
在类中加入成员变量flag,用来标记当前的状态,比如1表示happy,2表示excited等等,当一个行为是基于状态的时候,讨论flag的值,根据不同的值执行不同的操作。
这一方法的优点是当这个对象仅有极少的行为依赖状态时,使用这种方法逻辑简单,易于理解,组织结构也简单,状态改变方便,而且也易于维护。缺点是,一旦过多的行为依赖状态,就需要在每个行为中都加入判断,不易于维护,代码难看。
(2)同一对象不同状态抽象成不同的对象
举个例子,如果Person有happy和excited两种状态,可以定义HappyPerson和ExcitedPerson两个类,并定义不同的行为。
这样的优点是在行为较多时相对于(1),一个类的内部不再过于冗杂,逻辑更加清晰,在行为较多且都依赖状态、状态极少时适用。缺点是不易于改变状态,没有共同的基类不方便管理,而且一旦状态变多,就需定义很多的类,而且当对象的行为并不都依赖于状态时,不同类之前就会有对相同行为的重复定义。
(3)引入基础
在(2)的基础上做修改,定义抽象基类Person,将依赖状态的行为定义为纯虚函数,而不依赖状态的行为不定义为虚函数,希望子类直接继承。子类为HappyPerson、ExcitedPerson… 实现基类中的纯虚函数。
优点是,相对于(2)而言,更加灵活,对象本身和状态的耦合性减弱,但同样继承了(2)中的缺点,难于改变状态,而且对于更加复杂的类,状态和行为的耦合程度依然较高。
从前3点的补补递进,不难想到在更加复杂的情况下,使用多态是更好的方法,不过,对于简单问题,如果上述3种方法可以很好的解决问题,那么使用状态模式也不是必须的,使用状态模式也有产生较多的状态类这一缺点。具体用哪种方法还需要具体分析。
四、双向关联类
在上一次实验中,我也使用了双向关联类:Person和Group,其中Person和Group的成员中都含有存储对方指针的容器。
这次实验中的Person和State同样是双向关联的,Person中含有State的指针,而State中方法的参数是Person的指针。
解决这一问题的关键是:在使用任何类型和调用任何函数之前,它们的声明或者定义必须已经在调用之前存在。
由于双向关联,需要引入前向声明。经过前向声明之后的类型是不完全类型,对于不完全类型,实例化该类型的对象是非法的(不知道对象的大小,编译器无法分配空间),但是定义该类型的指针和引用是合法的(引用的底层实现就是指针,指针的大小就是一个字长,对指针的解释取决于编译器,在底层指针(或者地址)本身就是无类型)。因此,使用前向声明就可以解决这一问题,双向关联的类中不可能包含另一个关联类的对象类型。而对于函数调用的问题,只要拥有良好的分文件习惯,导入对方类的.h文件,就可以解决了。
- 面向对象程序设计第七次实验课——状态模式
- 面向对象程序设计第六次实验课——群与子群(装饰模式)
- 面向对象程序设计第四次实验课——socket初试
- 面向对象程序设计第五次实验课——深拷贝
- 面向对象程序设计第三次实验课——Wuxing
- 面向对象程序设计 第五次实验参考代码
- 面向对象程序设计 第六次实验参考代码
- C程序设计课程-第七次实验报告
- c程序设计第七次上机实验报告
- 第七次C程序设计实验报告
- C++第七次实验——作业
- 面向对象第四次实验
- JavaScript面向对象程序设计—创建对象的模式
- 面向对象程序设计第一次实验课——位运算封装
- 面向对象程序设计第二次实验课——mystring类实现
- 《面向对象程序设计》实验指导书
- Java 实验:面向对象程序设计
- 面向对象程序设计进阶——设计模式 design patterns
- CentOS7.2内核编译安装
- Unity GC优化学习(三):对象池技术与PoolManager插件
- tensorflow 中 sparse_softmax_cross_entropy_with_logits 与 softmax_cross_entropy_with_logits区别
- 现在,以编程方式在 Electron 中上传文件,是非常简单的!
- WebGL之旅(八)纹理映射
- 面向对象程序设计第七次实验课——状态模式
- 阿里云服务器注意事项
- RGB、YUV和YCbCr
- C++ STL之map与unordered_map
- ajax异步获取数据后动态向表格中添加数据(行)
- ajax异步获取数据后动态向表格中添加数据(行2) cheat-order.js
- 解决yum出现“No module named yum”错误方法
- yum 源
- 萌新的linux之旅10