我正在尝试学习装饰器模式,并将以下代码组合在一起。当我显式创建对象然后应用装饰器时(例如代码中的circleOne
和circleTwo
),它可以工作。
Circle c1{5.6};
ColoredShape cc1{c1, "green"};
TransparentShape circleOne{cc1, 67};
Circle c2{9.5};
TransparentShape tc2{c2, 25};
ColoredShape circleTwo{tc2, "yellow"};
但是,当我隐式创建对象(circleThree
和circleFour
)
TransparentShape circleThree{
ColoredShape{
Circle{50.6},
"green"
},
67
};
ColoredShape circleFour{
TransparentShape{
Circle{90.5},
25
},
"yellow"
};
然后,最终对象circleFour
将覆盖第三个对象circleThree
的数据。
完整代码如下:
#include <iostream>
using namespace std;
struct Shape {
virtual string str() const = 0;
};
struct Circle : Shape {
double radius;
explicit Circle(const double radius) :
radius{radius} {}
void resize(const double factor) { radius *= factor; }
string str() const override {
return "A circle of radius " + to_string(radius);
}
};
struct Square : Shape {
double length;
explicit Square(const double length) :
length{length} {}
void resize(const double factor) {
length *= factor;
}
string str() const override {
return "A square of side length " + to_string(length);
}
};
struct ColoredShape : Shape {
const Shape &shape;
string color;
ColoredShape(const Shape &shape, const string &color) :
shape{shape}, color{color} {}
//ColoredShape(Shape &&shape, const string &color) :
// shape{shape}, color{color} {}
string str() const override {
return shape.str() + " has the color " + color;
}
};
struct TransparentShape : Shape {
const Shape &shape;
int transparency;
TransparentShape(const Shape &shape, const int transparency) :
shape(shape), transparency(transparency) {}
//TransparentShape(Shape &&shape, const int transparency) :
// shape(shape), transparency(transparency) {}
string str() const override {
return shape.str() + " has " + to_string(transparency) +
"% transparency";
}
};
int main() {
Circle c1{5.6};
ColoredShape cc1{c1, "green"};
TransparentShape circleOne{cc1, 67};
Circle c2{9.5};
TransparentShape tc2{c2, 25};
ColoredShape circleTwo{tc2, "yellow"};
TransparentShape circleThree{
ColoredShape{
Circle{50.6},
"green"
},
67
};
ColoredShape circleFour{
TransparentShape{
Circle{90.5},
25
},
"yellow"
};
cout << circleOne.str() << endl;
cout << circleTwo.str() << endl;
cout << circleThree.str() << endl;
cout << circleFour.str() << endl;
return 0;
}
输出如下:
A circle of radius 5.600000 has the color green has 67% transparency
A circle of radius 9.500000 has 25% transparency has the color yellow
A circle of radius 90.500000 has 25% transparency has the color green has 67% transparency
A circle of radius 90.500000 has 25% transparency has the color yellow
如您所见,第三个圆的数据被第四个圆替换,并且透明装饰器被应用了两次。我该如何解决这个问题?
答案 0 :(得分:0)
首先,您的代码具有未定义的行为,因为您正在将临时对象传递给类的const ref成员。但是,当临时范围超出范围时,它会被销毁,并且您会有悬挂的引用。
这是错误的代码,
struct ColoredShape : Shape {
const Shape &shape;
string color;
ColoredShape(const Shape &shape, const string &color) : // const ref here !!!
shape{shape}, color{color} {}
//ColoredShape(Shape &&shape, const string &color) :
// shape{shape}, color{color} {}
string str() const override {
return shape.str() + " has the color " + color;
}
};
ColoredShape circleFour{
TransparentShape{ // this is a temporary
Circle{90.5},
25
},
"yellow"
};
答案 1 :(得分:0)
因此,您基本上有两个选择。
请勿装饰临时对象。最明显,最无聊。
使装饰器模板化,并根据需要使它们自己具有装饰形状:
template<class Decorated> class Colored: Shape {
std::string color;
Shape;
public:
Colored(Shape &&shape, std::string color): shape(std::forward<Shape>(shape)), color(std::move(color)) {}
};
template<class Decorated> Colored(Decorated &&, std::string) -> Colored<Decorated>;
这样,如果您进行构建
Colored greenCircle(Circle{1.0}, "green");
greenCircle
的类型推导为Colored<Circle>
,结果圆是其私有成员,并且如果您将其传递给已存在的对象,则为该对象
Circle c{2.0};
Colored redCircle(c, "red");
redCircle
的类型为Colored<Circle &>
,因此其成员只是对c
的引用。