基于输入条件动态筛选对象并选单对象的C#设计模式选型
推荐方案:命令模式 + 策略模式组合
针对你这种需要动态组合多步骤流程、根据输入跳过指定步骤的场景,我强烈推荐使用**命令模式(Command)搭配策略模式(Strategy)**的组合方案,完美匹配你的场景需求。
为什么选这两个模式?
你的核心需求有两个关键点:
- 每个筛选/调用步骤是独立的操作,但需要按顺序执行;
- 要根据输入值动态选择执行哪些步骤的组合。
- 命令模式:可以把每个步骤(比如“从数据库取列表”“调用外部HTTP服务”“业务规则筛选”等)封装成独立的「命令对象」,每个命令实现统一的执行接口,所有共享数据(比如当前对象列表、中间属性、输入参数)通过一个上下文对象传递。这样每个步骤的逻辑完全解耦,修改或新增步骤都不会影响其他代码。
- 策略模式:针对不同的输入值("1"、"2"、"3"等),定义对应的「策略类」,每个策略负责组装对应的命令序列(比如输入"1"就组装「步骤1→步骤5→步骤6」的命令列表)。调度时只需要根据输入选择对应的策略,就能自动执行对应的流程。
具体实现思路
1. 定义上下文类
先创建一个上下文类,用来存储所有共享数据,让所有步骤能共享和修改中间结果:
public class FilterContext { private String input; // 输入值,比如"1"/"2"/"3" private List<Object> objectList; // 当前的对象列表 private Object finalResult; // 最终选中的对象 // 可以添加其他需要共享的属性,比如外部服务返回的临时数据等 // getter/setter方法 }
2. 定义命令接口
所有步骤都实现这个统一的命令接口,保证执行方式一致:
public interface FilterStepCommand { void execute(FilterContext context); }
3. 实现每个步骤的命令类
把你的6个步骤分别封装成具体的命令:
FetchFromDbCommand:对应步骤1,从数据库获取对象列表并存入contextBusinessRuleFilterCommand:对应步骤2,根据业务规则筛选对象列表FirstExternalServiceCommand:对应步骤3,调用第一个外部HTTP服务,设置对象属性PostServiceFilterCommand:对应步骤4,基于步骤3的属性再次筛选SecondExternalServiceCommand:对应步骤5,调用第二个外部HTTP服务,设置对象属性FinalSelectCommand:对应步骤6,根据业务规则从列表中选单个对象存入context
每个命令类只负责自己的逻辑,比如FetchFromDbCommand的示例:
public class FetchFromDbCommand implements FilterStepCommand { @Override public void execute(FilterContext context) { // 这里写从数据库获取对象列表的逻辑 List<Object> dbList = ...; context.setObjectList(dbList); } }
4. 定义策略接口和具体策略类
策略接口负责返回对应输入值的命令序列:
public interface ExecutionStrategy { List<FilterStepCommand> getCommandSequence(); }
然后为每个输入值实现策略类,比如:
Input1Strategy:对应输入"1",返回「步骤1→步骤5→步骤6」的命令列表
public class Input1Strategy implements ExecutionStrategy { @Override public List<FilterStepCommand> getCommandSequence() { return Arrays.asList( new FetchFromDbCommand(), new SecondExternalServiceCommand(), new FinalSelectCommand() ); } }
Input2Strategy:对应输入"2",返回全部6个命令的列表Input3Strategy:对应输入"3",返回「步骤1→步骤2→步骤5→步骤6」的命令列表
5. 调度执行
最后写一个调度类,根据输入值获取对应的策略,然后依次执行命令序列:
public class FilterDispatcher { private Map<String, ExecutionStrategy> strategyMap; // 初始化时把输入值和对应的策略绑定 public FilterDispatcher() { strategyMap = new HashMap<>(); strategyMap.put("1", new Input1Strategy()); strategyMap.put("2", new Input2Strategy()); strategyMap.put("3", new Input3Strategy()); // 可以继续添加更多输入值对应的策略 } public Object execute(String input) { FilterContext context = new FilterContext(); context.setInput(input); ExecutionStrategy strategy = strategyMap.get(input); if (strategy == null) { throw new IllegalArgumentException("不支持的输入值"); } // 依次执行策略中的所有命令 for (FilterStepCommand command : strategy.getCommandSequence()) { command.execute(context); } return context.getFinalResult(); } }
方案优势
- 开闭原则:新增步骤只需要实现新的
FilterStepCommand,新增输入规则只需要实现新的ExecutionStrategy,完全不需要修改现有代码。 - 可维护性:每个步骤的逻辑独立,便于单独测试和修改,出问题时能快速定位到具体命令。
- 灵活性:可以轻松调整步骤的执行顺序,或者组合出更多自定义的流程,比如以后新增输入"4"只需要加一个新的策略类即可。
备选方案:责任链模式
如果你的步骤之间存在“某个步骤不满足条件就终止流程”的场景,也可以考虑责任链模式,但责任链更适合“请求沿着链条传递,直到被处理”的场景,而你的需求是固定顺序执行一组步骤,所以命令+策略的组合更贴合。
内容的提问来源于stack exchange,提问作者user641812




