当前位置: 首页 > news >正文

使用场景规则匹配模式代替复杂的if else条件判断

缘起

在业务处理程序中, 经常需要按照不同的场景有不同的处理方式, 在代码库中也充斥着大量的复杂的 if/else 语句, 这类代码可维护性非常差, 底层原因有:

  • 每个场景缺少定义,
  • 将场景识别和场景的应对代码耦合在一起。

解决方案

在代码中将场景明确化,将识别场景的条件与应对场景做隔离开来,

  • Scenario 类, 定义场景的基本信息, 比如场景名称、场景识别条件等。
  • ScenarioSelectionPolicyEnum 场景选择策略枚举, 比如选择高优先级场景, 还是低优先级场景, 还是返回所有符合条件的场景。
  • ISencarioRepository 接口:所有场景规则的存储库
  • ScenarioSelectionManager 类,按照场景选择策略, 将业务对象传入场景存储库中进行场景匹配。

示例代码

using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using System.Diagnostics.CodeAnalysis;class Test
{public static void Main(){ISencarioRepository ruleRepository = new BookDiscountRuleRepository();var bizRuleSelectionManager = new ScenarioSelectionManager(ruleRepository, ScenarioSelectionPolicyEnum.HighestPriorty);Book book1 = new Book(){Name = "book1",Category = "category1",PressHouse = "zhongxin",Price = 100};Book book2 = new Book(){Name = "book2",Category = "book2",PressHouse = "xxx",Price = 5};string traceMessage1;List<Scenario> selectedScenarioList1 = bizRuleSelectionManager.Select(book1, out traceMessage1);Console.WriteLine(book1.Name);Console.WriteLine(traceMessage1);}
}/// <summary>
/// 场景定义类
/// </summary>
public class Scenario
{/// <summary>/// 场景名, 要求唯一/// </summary>/// <value></value>public string Name { get; set; }/// <summary>/// 该场景是否被启用/// </summary>/// <value></value>public bool Enabled { get; set; } = true;/// <summary>/// 是否是默认场景/// </summary>/// <value></value>public bool IsDefault { get; set; } = false;/// <summary>/// 场景优先级/// </summary>/// <value></value>public int Priority { get; set; }/// <summary>/// 场景识别条件/// 函数传入一个业务对象, 返回值为boolean型,如果符合该场景则返回true/// </summary>/// <value></value>public Func<object, bool> Condition { get; set; } = null;/// <summary>/// 场景规则可以附带的信息, 比如针对打折场景, 可以附上折扣/// </summary>/// <value></value>public object Payload { get; set; } = null;public override string ToString(){return $"Name:{Name}";}}/// <summary>
/// 场景选择策略
/// </summary>
public enum ScenarioSelectionPolicyEnum
{AllMatched,HighestPriorty,LowestPriority,HighestPriortyOrDefault,LowestPriorityOrDefault,
}/// <summary>
/// 定义场景规则库的接口
/// </summary>
public interface ISencarioRepository
{public List<Scenario> BuildScenarioRepository();
}/// <summary>
/// 场景选择控制器
/// </summary>
public class ScenarioSelectionManager
{ScenarioSelectionPolicyEnum _policy;ISencarioRepository _scenarioRepository;List<Scenario> _scenarioList;private void CheckScenarioRepository(ScenarioSelectionPolicyEnum policy){//TODO://检查是否有同名的场景//检查是否有优先级相等的场景}private List<Scenario> SortScenarioList(){//TODO: 排序return _scenarioRepository.BuildScenarioRepository();}public ScenarioSelectionManager(ISencarioRepository scenarioRepository, ScenarioSelectionPolicyEnum policy){_scenarioRepository = scenarioRepository;_policy = policy;CheckScenarioRepository(policy);_scenarioList = SortScenarioList();}/// <summary>/// 按照策略来选择匹配的场景, 支持匹配多个场景以满足场景叠加需求/// </summary>/// <param name="bizObject"></param>/// <param name="traceMessage"></param>/// <returns></returns>public List<Scenario> Select(object bizObject, out string traceMessage){//TODO: 待完善traceMessage = "";List<String> notMatchedMsgList = new List<string>();var selectedScenarioList = new List<Scenario>();foreach (Scenario scenario in _scenarioList){if (scenario.Enabled == false){notMatchedMsgList.Add($"{scenario} disabled");}else if (scenario.Condition(bizObject)){selectedScenarioList.Add(scenario);}else{notMatchedMsgList.Add($"{scenario} not matched");}}var matchedStr = "";if (selectedScenarioList.Count != 0){matchedStr = string.Join(",", selectedScenarioList);matchedStr = $"Matched scenarios:{matchedStr}";}else{matchedStr = "No matched scenario";}var notMatchedStr = string.Join(",", notMatchedMsgList);notMatchedStr = $"Not matched scenarios:{notMatchedStr}";traceMessage = matchedStr + ", " + notMatchedStr;return selectedScenarioList;}
}/// <summary>
/// 图书类, 即业务对象类
/// </summary>
class Book
{public string Name { get; set; }public double Price { get; set; }public string PressHouse { get; set; }public string Category { get; set; }
}/// <summary>
/// 图书打折场景类, 即针对业务对象的场景规则库
/// </summary>
class BookDiscountRuleRepository : ISencarioRepository
{public List<Scenario> BuildScenarioRepository(){List<Scenario> lst = new();//场景1: 高价图书Scenario highPriceScenario = new Scenario(){Name = nameof(highPriceScenario),Enabled = true,Priority = 10,IsDefault = false,Condition = (obj) => (obj as Book).Price > 100,Payload = 0.5};lst.Add(highPriceScenario);//中信出版的图书Scenario ZhongxinPressScenario = new Scenario(){Name = nameof(ZhongxinPressScenario),Enabled = true,Priority = 10,IsDefault = false,Condition = (obj) => (obj as Book).PressHouse.ToUpper() == "ZHONGXIN",Payload = 0.6};lst.Add(ZhongxinPressScenario);//普调图书Scenario SunShineScenario = new Scenario(){Name = nameof(SunShineScenario),Enabled = true,Priority = 10,IsDefault = true,Condition = (object obj) =>{return true;},Payload = 0.9};lst.Add(SunShineScenario);return lst;}
}
http://www.hskmm.com/?act=detail&tid=19594

相关文章:

  • 9.28作业
  • 2025.9.28+7[未完]
  • 无需登录即可在管理员页面发现XSS漏洞的技术解析
  • 【操作系统】函数调用
  • 岐金兰与AI元人文概念的深度关联研究:从理论构想到实践应用
  • 维生素D,毛姆,我,还有停滞的3年
  • “一键并行搜索”的本地导航页实现
  • 常见NAS文件传输协议中SMB、FTP、NFS、 rsync、WebDAV服务各有何区别?
  • cgroup 使用
  • 在Java中原码反码补码的区别
  • 苍穹外卖-day02(新增员工,员工分页查询,启用禁用员工账号,编辑员工,导入分类模块功能代码) - a
  • 问题
  • 智慧决策的透明化路径:空白金兰契架构下的悟空备案制研究
  • 使用 preact 渲染组件到任何元素
  • 《ZeroTier教程》03-客户端配置 zerotier-cli常用命令 桥接和路由配置示例
  • XDG和桌面环境
  • JAVA 语法基础课程动手动脑及课后实验问题整理文档
  • python垃圾回收
  • Arduino IDE 离线更新ESP-32 lib包
  • CUDA编程(CUDA_By_Example笔记)
  • K8S部署Openwebui 服务(Nvidia版)
  • 传统AI对话:悟空也辛苦(ai元人文)
  • 理解大语言模型中的 Token
  • 软件工程第一次团队作业
  • 实验1作业
  • 苍穹外卖-day01(软件开发整体介绍,苍穹外卖项目介绍,开发环境搭建,导入接口文档,Swagger) - a
  • 9.27动手动脑及课后实验
  • idea必备插件
  • 新学期每日总结(第6天)
  • 第六天