Python运行时选择类执行方法的最优软件设计方案咨询
策略模式的典型场景:聊聊你的方案与替代思路
这是个非常典型的策略模式应用场景!先唠唠你想到的抽象基类+派生类方案的优缺点,再给你几个适配不同场景的替代思路。
你的抽象基类+派生类方案的优劣
优点
- 完美契合开闭原则:新增模拟行为只需要新建派生类,完全不用修改基类或现有代码,扩展性拉满,后续维护起来特别省心
- 职责划分清晰:每个派生类只对应一种模拟逻辑,代码可读性极强,别人接手一看就懂
- 天然适配类成员方法:彻底解决了函数指针没法直接复用类内部成员的问题,基类可以统一实现
doSomething这类通用逻辑,派生类只需要专注实现差异化的核心方法 - 性能开销极低:虽然是动态绑定,但因为启动时就确定了具体实例,运行时的虚函数调用开销几乎可以忽略,完全满足模拟程序的高效要求
缺点
- 类膨胀风险:如果后续要加几十种模拟行为,就得对应创建几十个派生类,项目里的类数量会激增,管理起来有点繁琐
- 初始化成本偏高:哪怕某个策略逻辑很简单,也得写一个完整的派生类(构造、析构、接口实现),有点“杀鸡用牛刀”的感觉
- 状态共享麻烦:如果不同策略之间需要共享复杂状态,虽然基类成员变量能解决一部分,但如果涉及跨策略的状态同步,可能得额外引入上下文类,增加复杂度
更优替代方案(按场景选择)
1. 函数对象/仿函数(轻量首选)
如果你的策略逻辑不算复杂,不需要太多内部状态,用函数对象或者lambda表达式封装策略会更轻量。比如(以C++为例):
// 定义策略类型 using BalancerStrategy = std::function<Result(const Object&)>; // 纯函数形式的策略 Result staticStrategy(const Object& obj) { // 实现静态逻辑 } Result dynamicStrategy(const Object& obj) { // 实现动态逻辑 } // 带内部状态的仿函数 class StaticBalancer { private: // 可以定义需要的内部状态 int someState; public: Result operator()(const Object& obj) { // 访问内部状态并实现逻辑 return /* ... */; } }; // 启动时选择策略 BalancerStrategy strategy; if (usedMethod == "static") { strategy = StaticBalancer(); // 或者直接用lambda:[](const Object& obj) { ... } } else { strategy = DynamicBalancer(); } // 模拟循环 BalancerClass balance; while(true) { Result result = strategy(object); balance.doSomething(input); }
这种方式不用创建一堆派生类,代码更简洁,同时也支持带状态的策略。
2. 类成员函数指针(极简场景)
如果你的差异化逻辑本来就是BalancerClass的成员方法,不需要额外状态,直接用成员函数指针就能搞定,完全不用额外类:
class BalancerClass { public: Result staticMethod(const Object& obj) { /* 静态逻辑 */ } Result dynamicMethod(const Object& obj) { /* 动态逻辑 */ } void doSomething(const Input& input) { /* 通用逻辑 */ } }; // 定义成员函数指针类型 using BalancerMethod = Result (BalancerClass::*)(const Object&); // 启动时选择方法 BalancerClass balance; BalancerMethod method; if (usedMethod == "static") { method = &BalancerClass::staticMethod; } else { method = &BalancerClass::dynamicMethod; } // 模拟循环 while(true) { Result result = (balance.*method)(object); balance.doSomething(input); }
这个方案最简洁,但缺点是没法给策略加额外的内部状态,适合逻辑简单、完全依赖原类成员的场景。
3. 模板方法模式(固定流程场景)
如果你的模拟循环流程是固定的,只有调用static/dynamic这一步不同,模板方法模式会更贴合。基类定义整个循环的框架,把差异化的步骤留作纯虚函数让派生类实现:
class BaseBalancer { public: void runSimulation(const Object& obj, const Input& input) { while(true) { Result result = coreLogic(obj); doSomething(input); // 其他固定流程逻辑 } } void doSomething(const Input& input) { /* 通用实现 */ } protected: virtual Result coreLogic(const Object& obj) = 0; // 差异化逻辑 }; class StaticBalancer : public BaseBalancer { protected: Result coreLogic(const Object& obj) override { /* 静态逻辑 */ } }; class DynamicBalancer : public BaseBalancer { protected: Result coreLogic(const Object& obj) override { /* 动态逻辑 */ } }; // 启动时实例化对应类 std::unique_ptr<BaseBalancer> balancer; if (usedMethod == "static") { balancer = std::make_unique<StaticBalancer>(); } else { balancer = std::make_unique<DynamicBalancer>(); } balancer->runSimulation(object, input);
这种方式把整个模拟流程封装在基类里,派生类只需要实现核心差异点,适合流程固定、后续扩展只改核心逻辑的场景。
总结
你的抽象基类+派生类方案是标准的策略模式实现,适合需要复杂状态管理、长期大量扩展的场景;如果策略逻辑简单,函数对象/成员函数指针更轻量;如果模拟流程固定,模板方法模式更合适。可以根据你的实际需求选最优解~
内容的提问来源于stack exchange,提问作者RoQuOTriX
相关产品推荐
相关产品推荐

