C++中策略与建造者模式及模板的设计问题咨询
C++策略+建造者模式几何对象方案问题解决与设计分析
一、模板参数导致的成员存储与setStrategy方法问题解决
核心思路是用类型擦除消除模板参数对建造者类的耦合:
- 重构策略接口:将带模板的
objreader_strategy改为非模板抽象基类,定义通用的解析操作纯虚函数,参数直接关联geometry对象:
class objreader_strategy { public: virtual ~objreader_strategy() = default; virtual void process_vertex(const std::string& line, geometry& geo) = 0; virtual void process_face(const std::string& line, geometry& geo) = 0; // 按需添加其他解析方法(如法向量、纹理坐标) };
- 调整模板策略子类:让
vec_strategy<T, L, S>继承上述基类,在实现中处理模板类型对应的解析逻辑:
template<typename T, size_t L, size_t S> class vec_strategy : public objreader_strategy { public: void process_vertex(const std::string& line, geometry& geo) override { // 基于T(数据类型)、L(顶点维度)解析顶点并写入geo } void process_face(const std::string& line, geometry& geo) override { // 基于S(面的顶点数)解析面数据并写入geo } };
- 修改建造者类:在
geometry_obj中存储基类智能指针作为策略成员,实现通用的setStrategy方法:
class geometry_obj : public geometry_creator { private: std::unique_ptr<objreader_strategy> current_strategy; geometry target_geo; public: void setStrategy(std::unique_ptr<objreader_strategy> strategy) { current_strategy = std::move(strategy); } void read_obj_file(const std::string& file_path) { if (!current_strategy) return; std::ifstream obj_file(file_path); std::string line; while (std::getline(obj_file, line)) { if (line.starts_with("v ")) { current_strategy->process_vertex(line, target_geo); } else if (line.starts_with("f ")) { current_strategy->process_face(line, target_geo); } // 其他行类型处理 } } geometry get_result() override { return std::move(target_geo); } };
外部调用时只需创建具体策略实例传入:
auto strategy = std::make_unique<vec_strategy<float, 3, 3>>(); geometry_obj builder; builder.setStrategy(std::move(strategy)); builder.read_obj_file("model.obj"); auto final_geo = builder.get_result();
二、避免多实例化vec_strategy,复用单一成员
上述方案天然支持单一策略成员复用:geometry_obj中的current_strategy是唯一的策略实例,所有解析操作都会复用它,无需每次调用方法时创建新对象。
如果策略是无状态的(不需要存储实例级数据),可以进一步用单例模式避免重复创建:
template<typename T, size_t L, size_t S> class vec_strategy : public objreader_strategy { public: static std::shared_ptr<vec_strategy> instance() { static auto inst = std::make_shared<vec_strategy>(); return inst; } // 禁止拷贝和赋值,确保单例唯一性 vec_strategy(const vec_strategy&) = delete; vec_strategy& operator=(const vec_strategy&) = delete; private: vec_strategy() = default; };
调用时直接传入单例指针:
builder.setStrategy(vec_strategy<float, 3, 3>::instance());
三、当前设计合理性分析
优点
- 模式适配性:策略模式封装不同解析规则(数据类型、顶点维度等),建造者模式管控几何对象的构建流程,两者解耦,符合单一职责原则。
- 扩展性:新增解析策略只需实现
objreader_strategy子类;新增几何对象建造源(如JSON、二进制文件)只需继承geometry_creator,完全符合开闭原则。 - 可测试性:抽象接口便于单元测试——可以模拟策略实现测试建造流程,也可单独测试策略的解析逻辑,无需依赖完整文件IO。
潜在优化点
- 类型安全:需确保
geometry类能兼容策略的模板类型(比如用多态容器、std::variant存储不同类型的顶点/面数据),避免类型不匹配导致的错误。 - 模板耦合简化:如果
geometry本身是强类型的(仅支持固定数据类型的顶点),可考虑将geometry和策略的模板参数绑定,进一步提升类型安全性。
内容的提问来源于stack exchange,提问作者Tristen Woodruff
相关产品推荐
相关产品推荐

