You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

基于输入条件动态筛选对象并选单对象的C#设计模式选型

推荐方案:命令模式 + 策略模式组合

针对你这种需要动态组合多步骤流程、根据输入跳过指定步骤的场景,我强烈推荐使用**命令模式(Command)搭配策略模式(Strategy)**的组合方案,完美匹配你的场景需求。

为什么选这两个模式?

你的核心需求有两个关键点:

  1. 每个筛选/调用步骤是独立的操作,但需要按顺序执行;
  2. 要根据输入值动态选择执行哪些步骤的组合。
  • 命令模式:可以把每个步骤(比如“从数据库取列表”“调用外部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,从数据库获取对象列表并存入context
  • BusinessRuleFilterCommand:对应步骤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

火山引擎 最新活动