图表类代码重构:样式提取后的设计问题及优化咨询
图表类结构重构的优化方案
原始类结构
class ChartBase { private: int transparency; //chart attribute }; class XYChart : public ChartBase{ private: std::string xAxis; std::string yAxis; }; class LineChart : public XYChart { private: int lineWidth; int lineColor; };
重构后的类结构
class StyleBase { private: int transparency; }; class XYStyle : public StyleBase { private: std::string xAxis; std::string yAxis; }; class LineStyle : public XYStyle { private: int lineWidth; int lineColor; }; class ChartBase { protected: std::shared_ptr<StyleBase> style; };
当前设计存在的问题
- 派生类(如
LineChart)需要将style指针强制转换为对应Style类型才能访问专属属性,类型不安全且代码繁琐。 - 每个Chart派生类必须在构造函数中替换
style实例,基类ChartBase中创建StyleBase的操作完全冗余,但XYChart的构造逻辑又必须保留(存在直接使用XYChart的场景)。
优化方案1:模板基类实现强类型Style访问
让ChartBase成为模板类,绑定对应的Style类型,派生类可直接获取强类型的Style引用,彻底避免强制转换:
// 定义抽象基类保证图表类的多态性(如果需要多态场景) class AbstractChart { public: virtual ~AbstractChart() = default; virtual void draw() = 0; }; template<typename TStyle> class ChartBase : public AbstractChart { protected: std::shared_ptr<TStyle> style; public: ChartBase() : style(std::make_shared<TStyle>()) {} }; class XYChart : public ChartBase<XYStyle> { public: void draw() override { // 直接访问 style->xAxis、style->yAxis,无需转换 } }; class LineChart : public ChartBase<LineStyle> { public: void draw() override { // 直接访问 style->lineWidth、style->lineColor,无需转换 } };
如果不需要多态,可以去掉AbstractChart,直接让派生类继承对应模板基类即可。
优化方案2:构造函数注入Style实例
让ChartBase通过构造函数接收Style实例,派生类根据需求传入对应类型的Style,消除基类的冗余构造:
class ChartBase { protected: std::shared_ptr<StyleBase> style; public: explicit ChartBase(std::shared_ptr<StyleBase> s) : style(std::move(s)) {} }; class XYChart : public ChartBase { public: XYChart() : ChartBase(std::make_shared<XYStyle>()) {} // 支持外部传入自定义XYStyle的重载构造 explicit XYChart(std::shared_ptr<XYStyle> s) : ChartBase(std::move(s)) {} }; class LineChart : public ChartBase { public: LineChart() : ChartBase(std::make_shared<LineStyle>()) {} // 支持外部传入自定义LineStyle的重载构造 explicit LineChart(std::shared_ptr<LineStyle> s) : ChartBase(std::move(s)) {} private: // 内部提供类型安全的Style访问方法,避免外部强制转换 LineStyle* getLineStyle() { auto ptr = std::dynamic_pointer_cast<LineStyle>(style); if (!ptr) { throw std::runtime_error("Invalid style type for LineChart"); } return ptr.get(); } public: // 对外提供类型安全的属性操作接口 void setLineWidth(int width) { getLineStyle()->lineWidth = width; } };
是否应该提取属性到Style类?
提取属性到独立的Style类是合理的,尤其适合以下场景:
- 需要为同一个图表实例切换不同样式配置。
- 多个图表实例需要共享相同样式配置(通过
shared_ptr可轻松实现)。 - 样式配置需要独立于图表逻辑进行复用、序列化或单独维护。
如果业务中没有上述需求,只是单纯拆分代码,原始结构可能更简洁;但如果有上述场景,当前的拆分方向正确,只需通过上述方案优化现有问题即可。
内容的提问来源于stack exchange,提问作者dxaw2000
相关产品推荐
相关产品推荐

