第十六章 无尽加班何时休--状态模式
16.1 加班又是加班!
上午状态好,中午想睡觉,下午渐恢复,加班苦煎熬。其实是一种状态的变化,在不同的时间,会有不同的状态。这些状态可以用状态模式来实现。
16.2 工作状态-函数版
在这个版本中是用面向过程来实现的。
代码1:
16.3 工作状态-分类版
将工作时间,是否完成工作任务这两个属性进行封装。实现了部分的面向对象。而写程序这个类还是面向过程的。
Work.h
#pragma once #include <iostream> class Work { public: void SetHour(int hour) { m_hour = hour; }; void SetFinish(bool finish) { m_finish = finish; }; int GetHour() { return m_hour; }; bool GetFinish() { return m_finish; }; void WriteProgram() { if (m_hour < 12) { std::cout << "当前时间:" << m_hour << "上午工作精神百倍" << std::endl; } else if (m_hour < 13) { std::cout << "当前时间:" << m_hour << "饿了犯困午休" << std::endl; } else if (m_hour < 17) { std::cout << "当前时间:" << m_hour << "下午状态还不错继续努力" << std::endl; } else { if (m_finish) { std::cout << "当前时间:" << m_hour << "下班回家了" << std::endl; } else { std::cout << "当前时间:" << m_hour << "不行了,睡着了" << std::endl; } } }; private: int m_hour; bool m_finish; };
Main函数
#include "stdafx.h" #include "Work.h" int _tmain(int argc, _TCHAR* argv[]) { Work* emergencyProject = new Work(); emergencyProject->SetHour(9); emergencyProject->WriteProgram(); emergencyProject->SetHour(10); emergencyProject->WriteProgram(); emergencyProject->SetHour(12); emergencyProject->WriteProgram(); emergencyProject->SetHour(13); emergencyProject->WriteProgram(); emergencyProject->SetHour(15); emergencyProject->WriteProgram(); emergencyProject->SetHour(17); emergencyProject->WriteProgram(); emergencyProject->SetFinish(false); emergencyProject->SetHour(19); emergencyProject->WriteProgram(); emergencyProject->SetHour(22); emergencyProject->WriteProgram(); return 0; }
16.4 方法过长是坏味道
如果一个方法很长,分支很多,这就意味着它的责任过大了。无论是任何状态,都需要通过它来改变,这样其实很糟糕。而面向对象设计气势就是希望做到代码的责任分解。
16.5 状态模式
当一个对象的内在状态改变时允许改变其行为,这个对象看起来像是改变了其类。状态模式主要解决的是当控制一个对象状态转换的条件表达式过于复杂的情况。把状态的判断逻辑转移到表示不同状态的一系列类当中,可以把复杂的判断逻辑简化。
Context.h
#pragma once #include "state.h" #include <iostream> class Context { public: Context(State* state) { m_pState = state; }; State* GetState() { return m_pState; }; void SetState(State* state) { if (m_pState != NULL) { delete m_pState; m_pState = NULL; } m_pState = state; std::cout << "当前的状态:" << m_pState->getClassName() << std::endl; }; void Request() { m_pState->Handle(this); } private: State* m_pState; };
state.h
#pragma once //#include "Context.h" class Context; class State { public: virtual void Handle(Context* context) = 0; virtual const char* getClassName() = 0; }; class ConcreteStateA :public State { public: void Handle(Context* context); const char* getClassName() { return "ConcreteStateA"; }; }; class ConcreteStateB :public State { public: void Handle(Context* context); const char* getClassName() { return "ConcreteStateB"; }; };
state.cpp
#include "state.h" #include "Context.h" void ConcreteStateA::Handle(Context* context) { context->SetState(new ConcreteStateB); }; void ConcreteStateB::Handle(Context* context) { context->SetState(new ConcreteStateA); };
Main函数
#include "stdafx.h" #include "context.h" int _tmain(int argc, _TCHAR* argv[]) { Context* state = new Context(new ConcreteStateB()); state->Request(); state->Request(); state->Request(); state->Request(); delete state; return 0; }
将特定的状态相关的行为都放入一个对象中,由于所有与状态相关的代码都存在于某个ConcreteState中,所以通过定义新的子类可以很容易地增加新的状态和转换。这样就消除了庞大的条件分支语句。
16.6 状态模式的好处与用处
状态模式的好处是将与特定状态相关的行为局部化,并且将不同状态的行为分割开来。当一个对象的行为取决于它的状态,并且它必须在运行时刻根据状态改变它的行为时,就可以考虑、用状态模式了。
16.7 工作状态-状态模式版
在这里主要有状态类,它定义了一个抽象方法写程序,上午和中午工作状态类,下午和傍晚工作状态类,还有其他一些状态类。而在工作类中,此时就没有了过长的分支判断语句了。
代码4
在这里如果要增加一个强制下班状态的时候,只要增加这个类并且改动一下傍晚工作状态类的判断就可以了。