如何使用装饰器模式直接修改base class的成员?
how to use decorator pattern to directly modify members of base class?
基地class答:
class A {
public:
A() {}
~A() {}
void methodOfA() { fill(array_.begin(), array_.end(), 100); }
private:
vector<int> array_;
};
装饰器class B:
class B: public A {
A* a_;
public:
B(A* a) { a_ = a; }
~B() {}
A* getA() { return a_; }
};
现在,如果我创建 B 的实例并按如下方式使用它:
A a;
B b(&a);
b.methodOfA();
我希望 b 访问或更改 a 拥有的所有内容。为此,可以使用:
b.getA()->methodOfA();
这对我来说不太好,有没有办法做类似的事情:
b.methodOfA();
但达到与b.getA()->methodOfA()相同的效果;请注意,A 可能没有用于将所有内容复制到 B 的复制构造函数,我希望在 a 中对 b 执行所有操作。
澄清一下:
如果我在 B 中覆盖 A 的每个成员函数(例如 methodOfA()),我可以实现上面我想要的。但是 A 中大约有 50 个函数需要覆盖。有没有更好的解决办法?
首先,A::methodOfA()
需要虚拟
然后,在B中,你需要添加这个:
virtual void methodOfA() { a_->methodOfA(); }
这就是装饰器模式。
理论上可能有一个实用程序,给定一个 class,自动为它生成一个装饰器,但我不知道有什么。
您可以做很多事情来减少 A
的方法数量,从而使编写装饰器更容易:
将多个不需要区别的方法合并为一个。例如,raiseFlag()
和lowerFlag()
可以变成setFlag( bool flag )
。
将A
的public接口提取到单独的classI
中,同时使A
和[=19] =] 扩展 I
。然后,去掉A
的实用方法(通过调用同一接口的其他方法实现的方法)放到I
中,并使它们成为非虚拟的。因此,您将引用一个 I
,它自己实现一些方法,(在其自身上调用其他方法,)并且这个 I
将由 B
的实例实现,其中每个虚拟方法委托(装饰)A
.
实例的相应虚拟方法
另请注意,通过为原始接口中的每个方法编写一个装饰器方法来实现装饰器模式的问题只是生活中的事实,与优雅无关。在工程中,优雅是关于避免黑客攻击,而不是关于节省击键。
我看到两个解决方案:
1 - 私有继承
struct A {
void stuff() {}
};
struct B : private A {
using A::stuff;
};
int main() {
B b;
b.stuff(); // OK
}
您需要列出所有 A
的方法,但您不必重新定义任何内容。
2 - 运算符重载
struct A {
void stuff() {}
};
struct B {
A *operator -> () {
return &a;
}
A a;
};
int main() {
B b;
b->stuff(); // Yuck. But OK.
}
一方面,如果不在 B
或其基础之一中实现 stuff
方法,就无法使用 b.stuff()
语法。另一方面,重载运算符对用户代码来说可能不直观。我想你必须选择你的毒药。
基地class答:
class A {
public:
A() {}
~A() {}
void methodOfA() { fill(array_.begin(), array_.end(), 100); }
private:
vector<int> array_;
};
装饰器class B:
class B: public A {
A* a_;
public:
B(A* a) { a_ = a; }
~B() {}
A* getA() { return a_; }
};
现在,如果我创建 B 的实例并按如下方式使用它:
A a;
B b(&a);
b.methodOfA();
我希望 b 访问或更改 a 拥有的所有内容。为此,可以使用:
b.getA()->methodOfA();
这对我来说不太好,有没有办法做类似的事情:
b.methodOfA();
但达到与b.getA()->methodOfA()相同的效果;请注意,A 可能没有用于将所有内容复制到 B 的复制构造函数,我希望在 a 中对 b 执行所有操作。
澄清一下: 如果我在 B 中覆盖 A 的每个成员函数(例如 methodOfA()),我可以实现上面我想要的。但是 A 中大约有 50 个函数需要覆盖。有没有更好的解决办法?
首先,A::methodOfA()
需要虚拟
然后,在B中,你需要添加这个:
virtual void methodOfA() { a_->methodOfA(); }
这就是装饰器模式。
理论上可能有一个实用程序,给定一个 class,自动为它生成一个装饰器,但我不知道有什么。
您可以做很多事情来减少 A
的方法数量,从而使编写装饰器更容易:
将多个不需要区别的方法合并为一个。例如,
raiseFlag()
和lowerFlag()
可以变成setFlag( bool flag )
。将
A
的public接口提取到单独的classI
中,同时使A
和[=19] =] 扩展I
。然后,去掉A
的实用方法(通过调用同一接口的其他方法实现的方法)放到I
中,并使它们成为非虚拟的。因此,您将引用一个I
,它自己实现一些方法,(在其自身上调用其他方法,)并且这个I
将由B
的实例实现,其中每个虚拟方法委托(装饰)A
. 实例的相应虚拟方法
另请注意,通过为原始接口中的每个方法编写一个装饰器方法来实现装饰器模式的问题只是生活中的事实,与优雅无关。在工程中,优雅是关于避免黑客攻击,而不是关于节省击键。
我看到两个解决方案:
1 - 私有继承
struct A {
void stuff() {}
};
struct B : private A {
using A::stuff;
};
int main() {
B b;
b.stuff(); // OK
}
您需要列出所有 A
的方法,但您不必重新定义任何内容。
2 - 运算符重载
struct A {
void stuff() {}
};
struct B {
A *operator -> () {
return &a;
}
A a;
};
int main() {
B b;
b->stuff(); // Yuck. But OK.
}
一方面,如果不在 B
或其基础之一中实现 stuff
方法,就无法使用 b.stuff()
语法。另一方面,重载运算符对用户代码来说可能不直观。我想你必须选择你的毒药。