【问题标题】:OO design in C++ - Decorating a parent object with unknown types of childC++ 中的 OO 设计 - 用未知类型的子对象装饰父对象
【发布时间】:2013-02-25 18:20:35
【问题描述】:

我目前正在开发一个系统,在该系统中对象沿贝塞尔曲线进行动画处理。在曲线上的各种用户定义点处,可能存在动画对象必须响应的事件。这可能是速度的变化、动画例程的变化、朝向的变化等......

到目前为止,我有以下 AnimationEvent 类。

class AnimationEvent
{
private:
    unsigned int    m_eventID;

    float   m_InteroplationPoint;

    float   m_SpeedInMPS;

public:
    AnimationEvent(unsigned int id, float interpolationPoint);
    ~AnimationEvent(void);

    const unsigned int getEventID();
    void setInterpolationPoint(float interpPoint);
    const float getInterpPoint();

    const float getSpeed();
};

每个事件都被分配为沿曲线的对象,当到达其插值点时,曲线类调用getSpeed() 函数以更改当前动画速度。

我真正想做的是实现一个系统,例如使用装饰器设计模式,其中可以用多个对象装饰事件,当达到时,将应用所有装饰。我遇到的问题是我无法将指向父对象的指针传递给子对象,因为这会创建一个循环依赖项,但我也有一个问题,我不知道(在编译时)什么类型的动作活动将被装饰。

任何关于如何克服这个问题的想法将不胜感激!如果我忘记了任何可能有帮助的信息,我会尝试编辑它。

【问题讨论】:

    标签: c++ oop design-patterns decorator


    【解决方案1】:

    如果您愿意跟踪对象之前发生的所有事件,您可以将类似装饰器的模式应用于此问题。您需要做的就是将每个事件存储在某种向量中。然后你可以做任何你想做的操作。

    #include <iostream>
    #include <vector>
    using namespace std;
    
    class Animatee;
    class AnimateEvent
    {
    public:
        virtual Animatee & perform(Animatee & on) = 0;
    };
    
    class Animatee
    {
    public:
        Animatee() : value(0){};
    
        void addEvent(AnimateEvent * event)
        {
            if(event != NULL)
            {
                events.push_back(event);
            }
    
        }
    
        Animatee & act()
        {
            for(vector<AnimateEvent * >::iterator it = events.begin(); it != events.end();++it)
            {
                AnimateEvent * event = *it;
                event->perform(*this);
            }
    
            return *this;
        }
    
        double value;   //don't do this, but something more encap'ed
    private:
    
        vector<AnimateEvent * > events;
    };
    
    class Add : public AnimateEvent
    {
        virtual Animatee & perform(Animatee & on)
        {
            on.value = on.value + 1;
            return on;
        }
    };
    
    class Subtract : public AnimateEvent
    {
        virtual Animatee & perform(Animatee & on)
        {
            on.value = on.value - 1;
            return on;
        }
    };
    
    class Multiply : public AnimateEvent
    {
        virtual Animatee & perform(Animatee & on)
        {
            on.value = on.value * 2;
            return on;
        }
    };
    
    class Div : public AnimateEvent
    {
        virtual Animatee & perform(Animatee & on)
        {
            on.value = on.value / 2.0;
            return on;
        }
    };
    
    int main() {
        Animatee matee;
        matee.addEvent(new Add());
    
        //cout << "Before: " << matee.value << " After: " << matee.act().value << endl; <~~~ Undefined btw, acting on the object twice in one "statement"
        double before = matee.value;
        cout << "Before: " << before << " After: " << matee.act().value << endl;
    
        matee.addEvent(new Subtract());
        before = matee.value;
        cout << "Before: " << before << " After: " << matee.act().value << endl;
    
        matee.addEvent(new Subtract());
        before = matee.value;
        cout << "Before: " << before << " After: " << matee.act().value << endl;
    
        matee.addEvent(new Add());
        matee.addEvent(new Add());
        matee.addEvent(new Add());
        before = matee.value;
        cout << "Before: " << before << " After: " << matee.act().value << endl;
    
        matee.addEvent(new Multiply());
        before = matee.value;
        cout << "Before: " << before << " After: " << matee.act().value << endl;
    
        before = matee.value;
        cout << "Before: " << before << " After: " << matee.act().value << endl;
    
        return 0;
    }
    

    【讨论】:

    • 俗称策略模式。
    • @MarkH 谢谢你,我以前从未听说过它被称为Strategy Pattern。维基百科条目显示的一些细微差别比我展示的要好。
    • 这个。这就是我来这里的原因。我没有想过使用策略模式,我想我的心思是在装饰上,我无法相信另一种模式可以帮助解决问题。前向声明也是我没有考虑过的。谢谢大卫!
    【解决方案2】:

    如上所述,您只支持一次可微分的速度函数,这看起来很可怕,除非有很多点。

    有两个不同的问题。第一个是内部动画参数的可能变化(可能对定位引擎来说应该是不透明的),第二个是速度的变化(不是不透明的)。

    我会正交解决这两个问题。

    关注速度,下一个问题是您希望装饰器如何相互组合。它们是加、乘、替换、形成输出速度的上限还是下限?

    他们可以访问哪些本地状态信息?

    假设他们被提供了沿曲线的位置,并且只有最后一个速度装饰器有意义,std::function&lt;double(double)&gt; 作为速度装饰器类型就可以了。

    这与调用一个或两个 virtual 函数的效率顺序相同。并且注入器或装饰器可以捕获任何它想要的内部状态......

    【讨论】:

      猜你喜欢
      • 2019-10-17
      • 1970-01-01
      • 1970-01-01
      • 2017-05-07
      • 2021-04-24
      • 1970-01-01
      • 1970-01-01
      • 2022-01-21
      • 1970-01-01
      相关资源
      最近更新 更多