我想知道你将如何解决这个问题:
我有一个班级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;
}
我的问题是:在运行时我需要向Foo“添加”新的(完全不同的)成员,具体取决于GUI的指令。我可以通过创建两个这样的“装饰器”来解决这个问题:
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命令使用每一个。但是,这样的更改会传播到我的所有代码中,并迫使我为使用Foo1
和Foo2
的每个类创建两个不同的版本(例如,我必须创建FooContainer1
和{ {1}})。
这种不太干扰的方法是创建
FooContainer2
并使用此代替class Bar: public Foo, public Decorator1, public Decorator2
{ }
。在这种情况下,我只调用Foo
和Decorator1
所需的函数而忽略其他函数,但这似乎违背了良好的OOP技术。
有关此问题的任何建议吗?
答案 0 :(得分: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。但是,如果您已正确编写客户端代码,则不需要这样做。
答案 1 :(得分: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;
答案 2 :(得分:0)
听起来你正在寻求处理mixin类型的功能。为此,您可以使用模板。在生成每个类的副本的意义上,这不是运行时,但它确实可以节省您的输入。
因此,对于每个装饰者,请执行以下操作:
template<class TBase> class Decorator1 : public TBase
{
public:
void NewMethod();
}
然后你可以,例如:
Foo* d = new Decorator1<Foo1>(...);
当然,在运行时使这项工作的唯一方法是决定你要创建哪种类型。不过,您最终仍然使用Foo
,Foo1
和Decorator1
类型,因此您可以根据需要在它们之间进行投射/使用RTTI。
有关详情,请参阅this article和this document
虽然我已经建议将其作为一种潜在的解决方案,但我个人很想接受多态性建议,如果可能的话 - 我认为这样可以更好,更容易维护代码,因为类实现的部分并不是分散的在所有地方使用mixins。只是我的两分钱 - 如果你认为它有效,那就去吧。
答案 3 :(得分:0)
类的基本概念是它被封装,因此在定义之后不能添加成员(尽管您可以使用多态并使用其他成员创建派生类,但它们无法通过原始类的指针:您必须将它们转换为派生的危险的),特别是在运行时。
所以在我看来,你的要求打破了OO编程的基本思想。这表明一个简单的解决方案:使用非成员函数。它们可以在任何时间定义,甚至可以在运行时定义(当您还需要编译它们时)。函数指针的开销与之前相同(当您需要指向新成员函数的指针时)。