• .NET:可扩展的单据编号生成器 + 简单的解释器


    背景

    在企业应用中单据编号的自定义是一个很常见的需求,能不能抽象一个通用的框架呢?之前写个一篇自定义密码强度的博文,感觉他们两个思路应该很相似。就让我们试试吧。

    思路

    这里的难点在于实现"解释器",比如将"前缀_<日期:yyyy_MM_dd>"解释为“工号生成器”,而且“解释器”的“规则”允许动态增加。

     

    实现

    代码下载

    类图

    核心代码

    CodeRuleGenerator.cs

     1 using System;
     2 using System.Collections.Generic;
     3 using System.Linq;
     4 using System.Text;
     5 using System.Threading.Tasks;
     6 
     7 using System.Text.RegularExpressions;
     8 
     9 namespace EntityCodeRuleDemo
    10 {
    11     public sealed class CodeRuleGenerator : ICodeRuleGenerator
    12     {
    13         private readonly IEnumerable<ICodeRuleProvider> _providers = new List<ICodeRuleProvider>();
    14 
    15         internal CodeRuleGenerator(IEnumerable<ICodeRuleProvider> providers)
    16         {
    17             _providers = providers;
    18         }
    19 
    20         public string Generate(object entity)
    21         {
    22             var sb = new StringBuilder();
    23 
    24             foreach (var provider in _providers)
    25             {
    26                 sb.Append(provider.Generate(entity));
    27             }
    28 
    29             return sb.ToString();
    30         }
    31     }
    32 }

    CodeRuleInterpreter.cs

     1 using System;
     2 using System.Collections.Generic;
     3 using System.Linq;
     4 using System.Text;
     5 using System.Threading.Tasks;
     6 
     7 using System.Text.RegularExpressions;
     8 
     9 using EntityCodeRuleDemo.RuleProviders;
    10 
    11 namespace EntityCodeRuleDemo
    12 {
    13     public static class CodeRuleInterpreter
    14     {
    15         private static Dictionary<Regex, Func<string, ICodeRuleProvider>> _providerFactorys = new Dictionary<Regex, Func<string, ICodeRuleProvider>>();
    16 
    17         static CodeRuleInterpreter()
    18         {
    19             SetProviderFactory(new Regex("^[^<].*?[^>]?$"), LiteralRuleProvider.LiteralRuleProviderFactory);
    20             SetProviderFactory(new Regex("^<日期(:(?<格式>.*?))?>$"), DateRuleProvider.DateRuleProviderFactory);
    21             SetProviderFactory(new Regex("^<属性(:(?<名称>.*?))?>$"), PropertyRuleProvider.PropertyRuleProviderFactory);
    22         }
    23 
    24         public static void SetProviderFactory(Regex regex, Func<string, ICodeRuleProvider> providerFactory)
    25         {
    26             _providerFactorys[regex] = providerFactory;
    27         }
    28 
    29 
    30         public static ICodeRuleGenerator Interpret(string codeRule)
    31         {
    32             var providers = GetProviders(codeRule);
    33 
    34             return new CodeRuleGenerator(providers);
    35         }
    36 
    37         private static IEnumerable<ICodeRuleProvider> GetProviders(string codeRule)
    38         {
    39             var literals = codeRule.Replace("<", "$<").Replace(">", ">$").Split('$');
    40 
    41             return literals
    42                 .Where(x => !string.IsNullOrEmpty(x))
    43                 .Select(GetProvider)
    44                 .ToList();
    45         }
    46 
    47         private static ICodeRuleProvider GetProvider(string literal)
    48         {
    49             var providerFactory = _providerFactorys
    50                 .FirstOrDefault(x => x.Key.IsMatch(literal))
    51                 .Value;
    52 
    53             if (providerFactory == null)
    54             {
    55                 throw new FormatException("格式化错误");
    56             }
    57 
    58             return providerFactory(literal);
    59         }
    60     }
    61 }

    Program.cs

     1 using System;
     2 using System.Collections.Generic;
     3 using System.Linq;
     4 using System.Text;
     5 using System.Threading.Tasks;
     6 
     7 namespace EntityCodeRuleDemo
     8 {
     9     class Program
    10     {
    11         static void Main(string[] args)
    12         {
    13             var employeeCode = CodeRuleInterpreter
    14                 .Interpret("前缀_<日期:yyyy_MM_dd>_<属性:NamePinYin>")
    15                 .Generate(new Employee { NamePinYin = "DUANGW" });
    16 
    17             Console.WriteLine(employeeCode);
    18         }
    19     }
    20 
    21     class Employee
    22     {
    23         public string NamePinYin { get; set; }
    24         public string EmployeeCode { get; set; }
    25     }
    26 }

    运行效果

    备注

    按照这种思路,基本上能满足企业应用的多数编码规则要求。在真实的项目中,这些规则是要持久化到数据库的,这样就可以做到运行时动态的修改规则了。

  • 相关阅读:
    Bash 小问题【待更新】
    进程动态优先级调度
    密码
    [Noi2016]优秀的拆分
    [Tjoi2016&Heoi2016]字符串
    [BZOJ 1901]Dynamic Rankings
    [HDU 2665]Kth number
    [BZOJ 4310]跳蚤
    [Sdoi2008]Sandy的卡片
    [Usaco2007 Dec]队列变换
  • 原文地址:https://www.cnblogs.com/happyframework/p/3073688.html
Copyright © 2020-2023  润新知