通过模板参数指定存储说明符(静态/非静态)避免C++代码重复的技术方案问询
解决静态/非静态包装类代码重复的方案
你的痛点我完全理解——维护两个几乎一模一样的类,只是一个带static一个不带,时间久了很容易出现代码不一致的问题,而且重复劳动也完全没必要。咱们可以通过提取公共逻辑+模板策略/特化的方式来解决这个问题,让所有核心逻辑只写一次,同时支持两种调用方式。
第一步:定义存储策略标记
先创建两个空的标记类型,用来告诉Wrapper类要使用哪种存储模式:
struct Locally {}; // 非静态:每个Wrapper实例拥有独立的worker struct Statically {}; // 静态:全局共享一个worker实例
第二步:提取公共业务逻辑
把DoSomeWork1()、DoSomeWork2()里的复杂逻辑单独抽出来,写成通用的实现函数。这些函数不关心worker是怎么来的,只需要一个能获取worker实例的"getter":
// 公共实现:所有复杂逻辑只写一次 template<typename WorkerGetter> void DoSomeWork1Impl(WorkerGetter&& getter) { // 这里写你的核心逻辑,比如: auto& worker = getter(); worker.Work1(); // 示例额外逻辑:记录日志、参数校验、结果处理等 // std::cout << "Work1 executed, result: " << worker.GetResult() << std::endl; // if (!worker.IsSuccess()) throw WorkFailedException(); } template<typename WorkerGetter> void DoSomeWork2Impl(WorkerGetter&& getter) { auto& worker = getter(); worker.Work2(); // 同样添加你的复杂逻辑... }
第三步:实现带策略的Wrapper类
通过模板特化,针对两种存储策略分别实现Wrapper,但所有业务方法都调用上面的公共实现,避免重复代码:
非静态版本(Locally策略)
每个Wrapper实例拥有自己的worker对象,方法是非静态的:
template<typename T> class Wrapper<Locally, T> { private: T m_Worker; // 实例独有的worker // 内部getter,给公共实现用 T& GetWorker() { return m_Worker; } public: // 允许默认构造(如果T支持的话) Wrapper() = default; // 如果T需要自定义构造参数,可以添加对应的构造函数 Wrapper(auto&&... args) : m_Worker(std::forward<decltype(args)>(args)...) {} void DoSomeWork1() { // 传递lambda作为worker getter,调用公共实现 DoSomeWork1Impl([this]() -> T& { return GetWorker(); }); } void DoSomeWork2() { DoSomeWork2Impl([this]() -> T& { return GetWorker(); }); } };
静态版本(Statically策略)
全局共享一个静态worker实例,方法是静态的:
template<typename T> class Wrapper<Statically, T> { private: // 全局唯一的静态worker,懒加载 static T& GetWorker() { static T worker; return worker; } public: static void DoSomeWork1() { // 传递静态getter的lambda,调用公共实现 DoSomeWork1Impl([]() -> T& { return GetWorker(); }); } static void DoSomeWork2() { DoSomeWork2Impl([]() -> T& { return GetWorker(); }); } };
第四步:使用方式
完全符合你想要的调用风格:
// 非静态使用:创建实例后调用方法 Wrapper<Locally, MyWorker> localWrap; localWrap.DoSomeWork1(); // 静态使用:直接通过类名调用静态方法 Wrapper<Statically, MyWorker>::DoSomeWork1();
为什么这个方案好用?
- 无代码重复:所有核心业务逻辑只在
Impl函数中写一次,两个Wrapper版本只是负责提供worker的获取方式,不会出现逻辑不一致的问题。 - 扩展性强:如果以后需要新增存储策略(比如线程局部存储的
ThreadLocal策略),只需要新增一个标记类型和对应的Wrapper特化,公共逻辑完全不用改。 - 调用清晰:通过模板参数明确指定存储模式,代码可读性高,别人一看就知道这个Wrapper是用实例还是静态方式。
额外说明
如果你的MyWorker需要自定义构造参数,静态版本的GetWorker()可以调整为支持参数注入,比如通过全局配置或者静态初始化函数,但这属于业务细节,不影响核心方案的结构。
内容的提问来源于stack exchange,提问作者Marc
相关产品推荐
相关产品推荐

