我正在尝试用类型类替换简单的枚举。也就是说,每个类型的基类派生一个类。例如,而不是:
enum E_BASE { EB_ALPHA, EB_BRAVO };
E_BASE message = someMessage();
switch (message)
{
case EB_ALPHA: applyAlpha();
case EB_BRAVO: applyBravo();
}
我想这样做:
Base* message = someMessage();
message->apply(this); // use polymorphism to determine what function to call.
我已经看到很多方法可以做到这一点,即使是基本的switch语句,它们看起来都不那么优雅。使用dyanimc_cast,从每次添加新消息时需要更新的messageHandler类继承,使用函数指针的容器,所有似乎都无法通过用多态替换开关来使代码更容易维护。
这是我能得到的:(我使用模板来避免从一个全知的处理程序接口继承)
class Base
{
public:
template<typename T> virtual void apply(T* sandbox) = 0;
};
class Alpha : public Base
{
public:
template<typename T> virtual void apply(T* sandbox)
{
sandbox->applyAlpha();
}
};
class Bravo : public Base
{
public:
template<typename T> virtual void apply(T* sandbox)
{
sandbox->applyBravo();
}
};
class Sandbox
{
public:
void run()
{
Base* alpha = new Alpha;
Base* bravo = new Bravo;
alpha->apply(this);
bravo->apply(this);
delete alpha;
delete bravo;
}
void applyAlpha() {
// cout << "Applying alpha\n";
}
void applyBravo() {
// cout << "Applying bravo\n";
}
};
显然,这不会编译,但我希望它能解决我的问题。
答案 0 :(得分:3)
好吧,在屈服于dynamic_cast和多重继承之后,我想到了Anthony Williams和jogear.net
class HandlerBase
{
public:
virtual ~HandlerBase() {}
};
template<typename T> class Handler : public virtual HandlerBase
{
public:
virtual void process(const T&)=0;
};
class MessageBase
{
public:
virtual void dispatch(HandlerBase* handler) = 0;
template<typename MessageType>
void dynamicDispatch(HandlerBase* handler, MessageType* self)
{
dynamic_cast<Handler<MessageType>&>(*handler).process(*self);
}
};
template<typename MessageType> class Message : public MessageBase
{
virtual void dispatch(HandlerBase* handler)
{
dynamicDispatch(handler, static_cast<MessageType*>(this));
}
};
class AlphaMessage : public Message<AlphaMessage>
{
};
class BravoMessage : public Message<BravoMessage>
{
};
class Sandbox : public Handler<AlphaMessage>, public Handler<BravoMessage>
{
public:
void run()
{
MessageBase* alpha = new AlphaMessage;
MessageBase* bravo = new BravoMessage;
alpha->dispatch(this);
bravo->dispatch(this);
delete alpha;
delete bravo;
}
virtual void process(const AlphaMessage&) {
// cout << "Applying alpha\n";
}
virtual void process(const BravoMessage&) {
// cout << "Applying bravo\n";
}
};
int main()
{
Sandbox().run();
return 0;
}
答案 1 :(得分:2)
看起来你正试图找到某种双调度系统。查看访客模式或其他多调度系统。
答案 2 :(得分:2)
你的Bravo和Alpha类实际上是关闭的......太糟糕的C ++不直接支持它们。
您可以使用成员指针执行此操作:
typedef void (Sandbox::*SandboxMethod)();
struct BrAlpha {
BrAlpha(SandboxMethod method) : method(method){}
void apply(Sandbox sb){sb->*method();}
};
BrAlpha alpha(&Sandbox::applyAlpha);
BrAlpha bravo(&Sandbox::applyBravo);
(语法可能不准确,但你知道我的意思是帽子)
答案 3 :(得分:0)
我不一定对你的设计模式问题有答案(尽管Modern C++ Design有很多话要说),但我确实希望解决你的转换与继承评论。
简单的swtich语句的问题是可维护性。如果那个switch语句在1个位置,那么它可能与创建类和继承的输入量大致相同,但是这个switch语句仍然是一个滴答作响的定时炸弹,等待另一个状态添加而没有为它添加一个案例。如果断言默认值:,你会在运行时捕获它 - 最终,但这很糟糕。如果你在表的大小上设置了一堆函数指针和编译时断言,那你就会做得更好,但这比switch语句更深。只要你在代码中有第二个位置需要检查状态,这一切就会全部消失。
一旦你的接口类设置让编译器处理内部开启状态的所有垃圾代码,这就容易多了。只要您按照界面添加该类就不必担心任何其他代码。