您的位置:首页 > 其它

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

2013-05-12 09:38 204 查看

背景

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

思路

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



实现

代码下载

类图



核心代码

CodeRuleGenerator.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

using System.Text.RegularExpressions;

namespace EntityCodeRuleDemo
{
public sealed class CodeRuleGenerator : ICodeRuleGenerator
{
private readonly IEnumerable<ICodeRuleProvider> _providers = new List<ICodeRuleProvider>();

internal CodeRuleGenerator(IEnumerable<ICodeRuleProvider> providers)
{
_providers = providers;
}

public string Generate(object entity)
{
var sb = new StringBuilder();

foreach (var provider in _providers)
{
sb.Append(provider.Generate(entity));
}

return sb.ToString();
}
}
}


CodeRuleInterpreter.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

using System.Text.RegularExpressions;

using EntityCodeRuleDemo.RuleProviders;

namespace EntityCodeRuleDemo
{
public static class CodeRuleInterpreter
{
private static Dictionary<Regex, Func<string, ICodeRuleProvider>> _providerFactorys = new Dictionary<Regex, Func<string, ICodeRuleProvider>>();

static CodeRuleInterpreter()
{
SetProviderFactory(new Regex("^[^<].*?[^>]?$"), LiteralRuleProvider.LiteralRuleProviderFactory);
SetProviderFactory(new Regex("^<日期(:(?<格式>.*?))?>$"), DateRuleProvider.DateRuleProviderFactory);
SetProviderFactory(new Regex("^<属性(:(?<名称>.*?))?>$"), PropertyRuleProvider.PropertyRuleProviderFactory);
}

public static void SetProviderFactory(Regex regex, Func<string, ICodeRuleProvider> providerFactory)
{
_providerFactorys[regex] = providerFactory;
}

public static ICodeRuleGenerator Interpret(string codeRule)
{
var providers = GetProviders(codeRule);

return new CodeRuleGenerator(providers);
}

private static IEnumerable<ICodeRuleProvider> GetProviders(string codeRule)
{
var literals = codeRule.Replace("<", "$<").Replace(">", ">$").Split('$');

return literals
.Where(x => !string.IsNullOrEmpty(x))
.Select(GetProvider)
.ToList();
}

private static ICodeRuleProvider GetProvider(string literal)
{
var providerFactory = _providerFactorys
.FirstOrDefault(x => x.Key.IsMatch(literal))
.Value;

if (providerFactory == null)
{
throw new FormatException("格式化错误");
}

return providerFactory(literal);
}
}
}


Program.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace EntityCodeRuleDemo
{
class Program
{
static void Main(string[] args)
{
var employeeCode = CodeRuleInterpreter
.Interpret("前缀_<日期:yyyy_MM_dd>_<属性:NamePinYin>")
.Generate(new Employee { NamePinYin = "DUANGW" });

Console.WriteLine(employeeCode);
}
}

class Employee
{
public string NamePinYin { get; set; }
public string EmployeeCode { get; set; }
}
}


运行效果



备注

按照这种思路,基本上能满足企业应用的多数编码规则要求。在真实的项目中,这些规则是要持久化到数据库的,这样就可以做到运行时动态的修改规则了。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: