3


我想知道您将如何解决这样的问题:

我有一堂课Foo

class Foo
{
public:
    Foo()  {   }
    ~Foo() {   }
    float member1() { return _member1; }
private: 
    float _member1;
    // other members etc...
}

一个容器类,其中包含一个指向 Foo 实例的指针容器

class FooContainer
{
public:
   FooContainer() {   }
   ~FooContainer() {   }
   void addFoo(Foo* f) {_foos.push_back(f);}
private:
   boost::ptr_vector<Foo> _foos;
}

我的问题是这样的:在运行时,我需要根据 GUI 的说明将新的(完全不同的)成员“添加”到 Foo。我可以通过创建两个这样的“装饰器”来解决这个问题:

class Decorator1
{
public:
   int   alpha() { return _alpha; }
   float beta()  { return _beta; }
private:
   int _alpha;
   float _beta;
}

class Decorator2
{
typedef std::complex<float> cmplx;
public:
   cmplx  gamma() { return _gamma; }
   double delta()  { return _delta; }
private:
   cmplx  _gamma;
   double _delta;
}

然后我会创建两个不同的 Foo 实现:

class Foo1 : public Foo, public Decorator1 
{   }

class Foo2 : public Foo, public Decorator2 
{   }

并根据 GUI 命令使用每一个。然而,这样的更改会传播到我的所有代码中,并会迫使我为每个使用Foo1and的类创建两个不同的版本Foo2(例如,我必须创建FooContainer1and FooContainer2)。

一种不那么侵入性的方法是创建

class Bar: public Foo, public Decorator1, public Decorator2
{   }

并使用它而不是Foo. 在这种情况下,我只会调用我需要的函数Decorator1Decorator2忽略其他函数,但这似乎与良好的 OOP 技术背道而驰。

关于这个问题的任何建议?

4

4 回答 4

8

你为什么不使用这样的简单多态性?

class Foo
{
public:
    Foo()  {   }
    virtual ~Foo() {   }
    float member1() { return _member1; }
private: 
    float _member1;
    // other members etc...
}

class Foo1 : public Foo
{   
    public:
   int   alpha() { return _alpha; }
   float beta()  { return _beta; }
private:
   int _alpha;
   float _beta;
}

class Foo2 : public Foo
{   
    typedef std::complex<float> cmplx;
public:
   cmplx  gamma() { return _gamma; }
   double delta()  { return _delta; }
private:
   cmplx  _gamma;
   double _delta;
}

class FooContainer
{
public:
   FooContainer() {   }
   ~FooContainer() {   }
   void addFoo(Foo* f) {_foos.push_back(f);}
private:
   boost::ptr_vector<Foo> _foos;
}

然后客户端代码不需要更改。根据 GUI 命令,您可以创建 Foo1 或 Foo2 并将其添加到单个容器中。如有必要,您可以使用 Foo 指针上的 dynamic_cast 来强制转换为 Foo1 或 Foo2。但是,如果您正确编写了客户端代码,则不需要这样做。

于 2012-07-06T13:51:14.713 回答
0

基于策略的模板怎么样?有一个将类作为模板参数的模板类 Foo。然后,有两个方法调用装饰器方法:

tempate <class Decor>
class Foo
{
public:
    Foo() : { __d = Decor()  }
    ~Foo() {   }
    float member1() { return _member1; }
    Decor::method1type decoratorMember1() { return __d.getValueMethod1();}
    Decor::method2type decoratorMember2() { return __d.getValueMethod2();}
private: 
    float _member1;
    Decor __d;
    // other members etc...
}

然后,在您的复杂装饰器中:

class Decor1 {
  typedef std::complex<float> method1type;
  typedef double method2type;
public:
  method1type getValueMethod1() {return _gamma}
  method2type getValueMethod2() {return _delta}
private:
  method1type _gamma;
  method2type _delta;
}

另一个也一样。这样,您的Foo代码可以添加任何内容,即使它已经编译。只需创建一个声明器类。而不是实例化Foo1,而是这样做:

Foo<Decor1> f;
于 2012-07-06T14:01:54.070 回答
0

类的基本概念是它是封装的,因此不能在定义之后添加成员(尽管您可以使用多态性并创建具有附加成员的派生类,但它们不能通过原始类的指针调用:您必须强制转换它们派生是危险的),尤其是在运行时。

所以在我看来,你的要求打破了 OO 编程的基本思想。这提出了一个简单的解决方案:使用非成员函数。它们可以在任何时候定义,甚至在运行时(当您还需要编译它们时)。函数指针的开销与以前相同(当您需要指向新成员函数的指针时)。

于 2012-07-06T14:16:42.087 回答
0

听起来您正在寻找处理 mixin 类型的功能。为此,您可以使用模板。从将生成每个类的副本的意义上说,这不是运行时,但它确实为您节省了打字时间。

因此,对于每个装饰器,请执行以下操作:

template<class TBase> class Decorator1 : public TBase
{
public:
    void NewMethod();
}

然后你可以,例如:

Foo* d = new Decorator1<Foo1>(...);

当然,在运行时完成这项工作的唯一方法是决定要创建哪种类型。但是,您仍然会得到 type FooFoo1因此Decorator1您可以在它们之间进行转换/根据需要使用 RTTI。

有关这方面的更多信息,请参阅本文本文档


尽管我建议将其作为一个潜在的解决方案,但如果可能的话,我个人会倾向于采用多态性建议——我认为这可以使代码更好、更容易维护,因为类实现的部分不会分散在整个使用 mixins 放置。只是我的两分钱 - 如果你认为它有效,那就去吧。

于 2012-07-06T14:05:59.803 回答