当前位置: 首页 > 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.rkmt.cn/news/13252.html

相关文章:

  • 【操作系统】函数调用
  • ABC425
  • 维生素D,毛姆,我,还有停滞的3年
  • cgroup 使用
  • US$34 PCAN Cable for ACDP Module3
  • US$39 CGPRO CAN V2.1 Adapter for CG Pro 9S12 Key Programmer
  • 使用 preact 渲染组件到任何元素
  • 《ZeroTier教程》03-客户端配置 zerotier-cli常用命令 桥接和路由配置示例
  • JAVA 语法基础课程动手动脑及课后实验问题整理文档
  • python垃圾回收
  • K8S部署Openwebui 服务(Nvidia版)
  • 9.27动手动脑及课后实验
  • NTT
  • 解决方案 | 无需安装任何插件,chrome如何快速搜索书签
  • Java语法基础课程动手动脑与实验问题深度解析
  • 课程中的所有动手动脑的问题以及课后实验性的问题
  • Java语法基础课程“动手动脑”问题与实验整理
  • 课后感想
  • Java基础核心问题 链接版
  • Python脚本生成包含标准的#ifndef保护宏的头文件
  • sg.帮我写一个类似于vb6窗体设计的PySimpleGUI布局设计助手
  • IP新定义下的商业新范式:基于定制开发开源AI智能名片S2B2C商城小应用的IP价值变现研究
  • mysql的单表多大要考虑分库分表
  • 无刷电机速度闭环控制
  • 微信小程序云开发 授权手机号快捷登陆
  • newDay05
  • AtCoder Beginner Contest 425 ABCDEF 题目解析
  • maven打包依赖
  • 对话汇总:从东方哲学到可计算架构的演进
  • 25.9.27 继续MyBatis