c++ - Correct use of friend for using multiple strategies without losing state?
问题描述
I have a class with some data, which I want to represent in different ways. There will always only be one representation active at a time, but I need to be able to change between them at runtime without losing internal state of any of the representations.
As a small example, let us use a chart. It can either be a pie-chart or a bar-chart, nothing else and only one at a time. I want to use the same data for both charts, but each of them represents the data differently. So both types of charts need their own rules for how to treat the data, which can change at runtime by the user.
I do not want to deal with each case in the chart class, but rather use something that handles every type of chart and calls the correct functions depending on the active one. All used variants of charts are known at compile time (two in this example).
A simple inheritance does not work, because the data is not shared between the charts. The strategy-pattern also does not quite work, because the state is lost upon switching charts and I need to preserve it. For the same reason std::variant
does not work in this case.
My current solution is similar to the strategy-pattern, but keeping each strategy alive in a manager class. Each strategy has a pointer to the chart class and is a friend of it to access the data:
struct Chart;
struct Strat {
explicit Strat(Chart* chart) : chart {chart} {}
virtual void foo() = 0;
Chart* chart;
};
struct Pie : public Strat {
explicit Pie(Chart* chart) : Strat {chart} {}
void foo() override { /* use chart->data */ }
};
struct Bar : public Strat {
explicit Bar(Chart* chart) : Strat {chart} {}
void foo() override { /* use chart->data */ }
};
struct Manager {
explicit Manager(Chart* chart) : pie {chart}, bar {chart} { strat = &pie; }
void changeToBar() { strat = &bar; }
void foo() { strat->foo(); }
Strat* strat;
Pie pie;
Bar bar;
};
struct Chart {
Chart() : manager {this} { manager.foo(); }
void changeToBar() { manager.changeToBar(); }
void foo() { manager.foo(); }
friend Pie; // friends to make data accessible
friend Bar;
private:
Manager manager;
int data = 42; // private data, shared by all strats
};
int main() {
Chart chart; // inititally pie chart
chart.foo(); // do pie stuff
chart.changeToBar(); // now bar chart, but keep pie alive
chart.foo(); // do bar stuff
}
To me it feels like there is a better solution to do the same thing, but I could not find it, so my question is: is this the correct way of dealing with multiple strategies, while preserving the state?
解决方案
我想您已经想到了这一点,但是您可以创建一个指向您的数据结构的共享指针,并将其传递给您的所有图表结构。任何新的图表类型都将很容易添加,只需传递相同的指针。如果您在图表构造函数中传递数据结构指针,那么当您的客户在路上请求新的图表类型时,它也可以作为自我文档。
推荐阅读
- swift - 一个uicollectionview单元格上有一个uitableview时的过渡方法
- php - 无法从谷歌分析中读取
- javascript - 删除鼠标悬停时添加的带有悬停和动画结束的类
- android - React Native:找不到支持向量drawable.aar
- javascript - Javascript不会获得递增的变量值,而是使用定义的值
- r - Choropleth 在地图上使用 ggplot2 R 绘制多边形
- java - Android 包签名不匹配
- python - 在烧瓶中处理自定义验证的正确方法是什么?
- css - 为什么从 CDN 加载的 Office UI Fabric Core CSS 图标不一致?
- docker - 使用 docker compose 运行 Gatsby