背景
在企业应用中单据编号的自定义是一个很常见的需求,能不能抽象一个通用的框架呢?之前写个一篇的博文,感觉他们两个思路应该很相似。就让我们试试吧。
思路
这里的难点在于实现"解释器",比如将"前缀_<日期: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 EntityCodeRuleDemo10 {11 public sealed class CodeRuleGenerator : ICodeRuleGenerator12 {13 private readonly IEnumerable_providers = new List ();14 15 internal CodeRuleGenerator(IEnumerable 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 EntityCodeRuleDemo12 {13 public static class CodeRuleInterpreter14 {15 private static Dictionary> _providerFactorys = new Dictionary >();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 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 名称> 属性(:(?> 格式> 日期(:(?>GetProviders(string codeRule)38 {39 var literals = codeRule.Replace("<", "$<").Replace(">", ">$").Split('$');40 41 return literals42 .Where(x => !string.IsNullOrEmpty(x))43 .Select(GetProvider)44 .ToList();45 }46 47 private static ICodeRuleProvider GetProvider(string literal)48 {49 var providerFactory = _providerFactorys50 .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 Program10 {11 static void Main(string[] args)12 {13 var employeeCode = CodeRuleInterpreter14 .Interpret("前缀_ <日期:yyyy_mm_dd> _ <属性:namepinyin> ")15 .Generate(new Employee { NamePinYin = "DUANGW" });16 17 Console.WriteLine(employeeCode);18 }19 }20 21 class Employee22 {23 public string NamePinYin { get; set; }24 public string EmployeeCode { get; set; }25 }26 } 属性:namepinyin> 日期:yyyy_mm_dd>
运行效果
备注
按照这种思路,基本上能满足企业应用的多数编码规则要求。在真实的项目中,这些规则是要持久化到数据库的,这样就可以做到运行时动态的修改规则了。