假设我有一个抽象基类State
和至少两个派生类AnimalState
和PlantState
(也是抽象的)。另外,我有许多来自AnimalState
和PlantState
的派生类。
class State{} // abstract
class AnimalState: public State{} // abstract
class PlantState: public State{} // abstract
//maybe few more of such classes here
class AnimalStateSpecific1: public AnimalState{}
class AnimalStateSpecific2: public AnimalState{}
... //many of them
class PlantStateSpecific1: public PlantState{}
class PlantStateSpecific2: public PlantState{}
... //many of them
现在,假设我在基于State
指针的某种方法中使用它们。随着时间的推移,这些指针将被其他指向State
层次结构中不同类的指针所取代。根据某些规则,特别是在预定义的状态图中,它会发生。
现在到问题部分。为了确定下一个状态,我需要知道上一个状态。但是由于我只有基本的State
指针,因此如果不对层次结构中不好的每个派生类进行dynamic_cast
的操作,就无法有效地知道自己的状态类型。我可以拥有一些具有各种状态的enum
,但是我真的不喜欢那样,因为我不想混合来自两个层次结构分支的信息,因为这确实是不同的。另外,对于层次结构中的每个分支,例如enums
,AnimalStateEnum
等,我都不喜欢不同的PlantStateEnum
。
此问题的最佳解决方案是什么?也许我的设计从一开始就不好?我想使其尽可能通用,并且仅在可能的情况下仅与基类对象一起使用。
答案 0 :(得分:2)
现在到问题部分。为了确定下一个状态,我需要知道上一个状态。
基于我们拥有的有限信息的最简单解决方案-对象,它知道自己的状态会创建下一个状态对象:
awscli 1.15.66
blessed 1.15.0
botocore 1.10.65
cement 2.10.12
certifi 2018.4.16
chardet 3.0.4
colorama 0.3.9
docker-py 1.10.6
docker-pycreds 0.3.0
dockerpty 0.4.1
docopt 0.6.2
docutils 0.14
idna 2.7
jmespath 0.9.3
pathspec 0.5.6
pip 18.0
pyasn1 0.4.4
python-dateutil 2.7.3
PyYAML 3.13
requests 2.19.1
rsa 3.4.2
s3transfer 0.1.13
semantic-version 2.6.0
setuptools 40.0.0
six 1.11.0
texttable 1.4.0
urllib3 1.23
wcwidth 0.1.7
websocket-client 0.48.0
wheel 0.31.1
然后在从class State{
public:
...
virtual std::unique_ptr<State> transform( some data ) = 0;
};
类派生的每个类中实现它,可以更改它的状态并知道它可以移动到哪里。您需要传递什么数据不是一个简单的问题-它取决于您的任务,并且可能具有各种选项,但是您需要定义一些可以被所有派生类使用的东西,因为签名是在基类上定义并在所有派生的。
此问题的最佳解决方案是什么?也许我的设计从一开始就不好?
这个问题并不简单,只有对您的任务有很深的知识才能回答。如果不确定,请实施原型并检查解决方案是否完全适合您的问题。不幸的是,学习如何创建好的设计的唯一方法是您自己的经验(当然,平凡的情况除外)。
答案 1 :(得分:1)
您可以在状态类层次结构中简单地使用虚拟方法next()
,
然后执行类似于以下示例的操作:
State *globalState = nullptr;
void foo(State *s)
{
globalState = s->next();
}
每个派生类将按照其自身的含义实现next()
:
PlantStateSpecific1 *AnimalStateSpecific1::next(){ return new PlantStateSpecific1; }
AnimalStateSpecific1 *PlantStateSpecific1::next(){ return new AnimalStateSpecific1; }
与拥有派生类的枚举/整数描述符相比,这是更多的OOP。
答案 2 :(得分:0)
您可以在基态类中包含一个整数,该类下的每个类都将在其构造函数中设置该整数。然后,您可以使用常量的Sereis,具有与状态类型索引相对应的ID的可能状态的列表,或使用枚举器。 id更加灵活,因为您可以相对轻松地创建状态类型并轻松地对其进行添加处理,以及您希望从id类型创建新状态。
iv以前只是这样做的一种方式,但可能还有很多其他方式。