多条件组合选择操作的最佳设计模式选型咨询
多维度枚举条件路由场景的落地方案
你当前遇到的是典型的多条件组合路由问题,多层嵌套if-else的核心问题是条件判断逻辑和业务操作强耦合,新增规则、新增判断维度时必须侵入原有分支代码,维护成本会随规则量上涨指数级上升。结合你提到的「枚举取值固定、未来可能新增判断维度」的特点,推荐两个可直接落地的方案,优先选第一个即可。
方案1:规则谓词 + 策略模式(适配90%以上同类场景,扩展成本最低)
核心思路是把「条件判断」和「操作执行」完全拆解开,所有规则平铺注册,没有嵌套逻辑:
- 把每个带固定参数的业务操作抽象成独立的策略类,统一实现操作接口,类内部只写执行逻辑,不关心触发条件
- 每个规则由「匹配谓词」「优先级」「对应操作」三部分组成,匹配谓词用通用的委托/函数实现,不限制判断维度数量
- 启动阶段按优先级从高到低注册所有规则,执行时遍历规则列表,第一个匹配成功的规则就触发对应操作
核心代码实现(C#,和你原有代码风格一致)
// 1. 统一操作接口 public interface IOperation { void Execute(Item item); } // 2. 具体操作实现,参数直接封装在操作类内部 public class Rotate45Operation : IOperation { public void Execute(Item item) => item.Rotate(45); } public class Rotate90Operation : IOperation { public void Execute(Item item) => item.Rotate(90); } public class Scale2Operation : IOperation { public void Execute(Item item) => item.Scale(2); } public class DeleteOperation : IOperation { public void Execute(Item item) => item.Delete(); } public class GlowOperation : IOperation { public void Execute(Item item) => item.Glow(); } // 3. 规则定义 public class OperationRule { // 优先级数值越小,匹配优先级越高 public int Priority { get; set; } public Func<Item, bool> MatchCondition { get; set; } public IOperation ExecOperation { get; set; } } // 4. 核心执行器 public class ItemOperationExecutor { private readonly List<OperationRule> _ruleSet = new(); // 注册规则方法,启动初始化时调用 public void AddRule(int priority, Func<Item, bool> condition, IOperation operation) { _ruleSet.Add(new OperationRule { Priority = priority, MatchCondition = condition, ExecOperation = operation }); // 每次注册后按优先级重排规则 _ruleSet.Sort((a,b) => a.Priority.CompareTo(b.Priority)); } // 对单个条目执行匹配到的操作 public void RunForItem(Item item) { foreach (var rule in _ruleSet) { if (rule.MatchCondition(item)) { rule.ExecOperation.Execute(item); // 如果需要支持单个条目触发多个操作,删掉下面的break即可 break; } } } }
规则注册示例(完全对应你原有业务逻辑)
程序启动时完成规则注册即可,所有逻辑平铺可见,没有嵌套:
var executor = new ItemOperationExecutor(); // 优先级最高:三维度精准匹配规则 executor.AddRule(1, item => item.Dimension == Dimensions.D3 && item.Color == Colors.Red && item.Shape == Shapes.Round, new DeleteOperation()); executor.AddRule(2, item => item.Dimension == Dimensions.D3 && item.Color == Colors.Red && item.Shape == Shapes.Square, new GlowOperation()); // 次优先级:两维度匹配规则 executor.AddRule(3, item => item.Dimension == Dimensions.D2 && item.Color == Colors.Green, new Rotate45Operation()); executor.AddRule(4, item => item.Dimension == Dimensions.D3 && item.Color == Colors.Green, new Rotate90Operation()); executor.AddRule(5, item => item.Dimension == Dimensions.D2 && item.Color == Colors.Blue, new Scale2Operation()); // 如果要加单维度通用规则(比如所有绿色对象都执行rotate),直接注册更低优先级的规则即可 // 未来新增判断维度(比如材质、大小),只需要在新规则的谓词里加对应判断即可,核心执行逻辑完全不用改
替换后你原来的业务循环会非常干净:
case SomeCase: foreach(var item in items){ executor.RunForItem(item); } break;
方案优势
- 没有嵌套逻辑,扫一遍规则注册代码就能看清所有业务映射关系,可读性远高于多层if-else
- 新增操作、新增规则完全不需要修改原有执行逻辑,符合开闭原则
- 扩展新的判断维度没有改造成本,不需要调整核心框架代码
- 后续如果需要把规则迁移到配置文件、数据库做动态配置,只需要改规则加载逻辑,上层执行代码无感知
方案2:维度通配查表法(适合规则量极大、对匹配性能有极致要求的场景)
如果后续规则量上涨到上百条,遍历匹配的性能不能满足要求,可以换查表方案:
- 按维度顺序生成结构化的条件键,比如用
|分割各维度取值,用*代表通配(匹配该维度任意值),比如3D|Red|Round、2D|Green|*、*|Green|*都是合法的键 - 用字典存储「条件键-对应操作」的映射关系,提前按精准度给键排好优先级(维度上通配符越少,优先级越高)
- 执行时按优先级顺序生成当前条目对应的候选键,在字典里查到匹配项就执行操作
这个方案的匹配性能是O(1),但前期需要写好维度键生成、通配优先级排序的逻辑,灵活度比方案1稍差,规则量小的时候没必要用。
避坑说明
不要硬套访问者模式、责任链模式解决这个问题:访问者模式新增判断维度时需要修改所有元素的访问接口,和你未来要加维度的需求完全相悖;纯责任链模式需要把每个判断逻辑写成单独的链节点,规则多了之后链路过长,维护成本不比if-else低。Builder模式的适用场景是构建复杂对象,和当前条件路由的需求完全不匹配,不需要考虑。
内容的提问来源于stack exchange,提问作者GrfPT4
相关产品推荐
相关产品推荐

