我有一个动画类。我需要在动画中为Play
,Pause
和Stop
事件设置一些观察者。我找到了2个解决这个问题的方法,但我不知道该选择什么。
使用boost :: signals或类似的东西并为每个事件注册回调
使用3个纯虚函数(OnPlay()
,OnPause()
,OnStop()
创建一个简单的接口,并传递给实现此接口的Animation类对象。
每种方法都有优点和缺点。我将尝试列举到目前为止我发现的那些:
1的优势。
1的缺点
2的优点。
2的缺点。
你能告诉我使用什么吗?从您的经验来看,对于这个问题有什么好处 - 从第一个方面获得免费或者从第二个方面获得清晰易懂的代码?您能否告诉我这两种方法或其他解决方案的其他优点/缺点?
答案 0 :(得分:3)
首先,知道在编译时是否知道“绑定”是有用的。如果是这样,我建议你研究政策类。
除此之外,我会考虑两种解决方案的混合,即使用接口方法并实现一个接口,充当信号/自由功能的中继器。通过这种方式,您可以拥有默认行为,您可以添加实现整个界面的自定义对象,并且基本上具有这两种方法的优点以及更大的灵活性。
以下是提议方法的基本示例,我希望它有所帮助。
#include <functional>
using namespace std;
template <class ObserverPolicy>
class Animation : public ObserverPolicy{
};
class MonolithicObserver{
public:
void play(){
state = playing;
}
void pause(){
if(playing == state)
state = stopped;
}
void stop(){
state = stopped;
}
private:
enum {playing, paused, stopped} state;
};
struct doNothing{
static void play(){}
static void pause(){}
static void stop(){}
};
struct throwException{
class noPlay{};
class noPause{};
class noStop{};
static void play(){
throw noPlay();
}
static void pause(){
throw noPause();
}
static void stop(){
throw noStop();
}
};
template <class DefaultPolicy = doNothing>
class FreeFunctionObserver{
public:
void play(){
if(playHandle)
playHandle();
else
DefaultPolicy::play();
}
void pause(){
if(pauseHandle)
pauseHandle();
else
DefaultPolicy::pause();
}
void stop(){
if(stopHandle)
stopHandle();
else
DefaultPolicy::stop();
}
void setPlayHandle(std::function<void(void)> p){
playHandle = p;
}
void setPauseHandle(std::function<void(void)> p){
pauseHandle = p;
}
void setStopHandle(std::function<void(void)> p){
stopHandle = p;
}
private:
std::function<void(void)> playHandle;
std::function<void(void)> pauseHandle;
std::function<void(void)> stopHandle;
};
void play(){}
void pause(){}
void stop(){}
int main(){
Animation<FreeFunctionObserver<> > affo;
affo.setPlayHandle(play);
affo.setPauseHandle(pause);
affo.setStopHandle(stop);
affo.play();
affo.pause();
affo.stop();
Animation<FreeFunctionObserver<throwException> > affot;
try{
affot.play();
}
catch(throwException::noPlay&){}
Animation<MonolithicObserver> amo;
amo.play();
amo.pause();
amo.stop();
}
您可以尝试here。特别是,这个例子使用了一个策略类(因此没有“正式”定义接口,你可以“丰富”接口,就像使用setPlayHandle一样)。但是,您也可以使用运行时绑定执行类似的操作。
答案 1 :(得分:1)
除了最简单的玩具示例之外,Boost.Signals2在我看来是最好的解决方案。它设计精良,经过充分测试并且记录完备。重新制作轮子对于家庭作业类型的练习很有用,但不适用于生产代码。例如。让你自己的观察者线程安全是非常重要的,以获得正确和有效。
具体讨论您列出的缺点
boost::bind
语法(对于大多数用法来说这并不是很复杂)。TL; DR :熟悉Boost.Signals2
答案 2 :(得分:0)
我认为,您可以使用两者:)但这取决于需求。我有一些代码,我使用这两种模式。有许多函数叫做onSomething()(onMouseButton(),onKey(),onDragStart()等),但也有回调。当我需要实现某些行为时,但对于整个类的对象,我使用onSomething()方法。但是如果我有一堆相同类的对象,但只有部分对象需要扩展功能 - 回调是一个完美的方法。
在实施中,它是这样完成的: 有一些调度代码尝试使用onSomething()方法(返回bool),如果结果为false - 那么检查是否定义了回调,如果是,则执行。