正确使用朋友使用多种策略而不会丢失状态?

Correct use of friend for using multiple strategies without losing state?

本文关键字:状态 策略 朋友      更新时间:2023-10-16

我有一个包含一些数据的类,我想以不同的方式表示这些数据。一次总是只有一个表示处于活动状态,但我需要能够在运行时在它们之间更改,而不会丢失任何表示的内部状态。

作为一个小例子,让我们使用图表。它可以是饼图或条形图,没有别的,一次只能有一个。我想对两个图表使用相同的数据,但它们中的每一个都以不同的方式表示数据。因此,这两种类型的图表都需要自己的规则来处理数据,用户可以在运行时更改这些规则。

我不想处理图表类中的每个情况,而是使用处理每种图表并根据活动图表调用正确函数的东西。所有使用的图表变体在编译时都是已知的(在本例中有两个(。
简单继承不起作用,因为数据不在图表之间共享。策略模式也不太有效,因为切换图表时状态会丢失,我需要保留它。出于同样的原因,std::variant在这种情况下不起作用。

我目前的解决方案类似于策略模式,但使每个策略都保持在经理类中。每个策略都有一个指向图表类的指针,并且是它访问数据的朋友:

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
}

对我来说,感觉有更好的解决方案来做同样的事情,但我找不到它,所以我的问题是:这是处理多种策略的正确方法,同时保持状态吗?

我想你已经想到了这一点,但你可以创建一个指向数据结构的共享指针,并将其传递给所有的图表结构。 然后,任何新的图表类型都可以轻松添加,只需传递相同的指针即可。 如果您在图表构造函数中传递数据结构指针,那么当您的客户端请求新的图表类型时,它也会自行文档。