模式应用:自定义匹配

 本篇博客记录了我在工作过程中的一个设计单元。


需求

    GIX4项目中需要为非国标清单进行匹配,用户自定义匹配规则。规则可以被存储到数据库中,下次重复使用。界面原型如下:

图1 界面原型

    用户可以指定对对象的某属性进行某个比较操作。


设计-总体结构

图2 总体结构

    看上去会有点晕?懒了一点,就全画一起了。 :o)

    中间的接口就是整个结构的核心所在,下面会详细解释:


第一组接口:设计匹配概念

    首先,明确匹配的概念,这个概念是与GIX4应用无关的。 一个是可以被匹配的对象,另一个则是主动匹配者。如下:

/// <summary>
/// 被匹配的对象
/// </summary>
public interface IMatchTarget { }

/// <summary>
/// 可以实施匹配操作的类。
/// </summary>
public interface IMatchable
{
    /// <summary>
    /// 是否已经匹配过了。
    /// </summary>
    bool HasMatched { get; }

    /// <summary>
    /// 开始匹配
    /// </summary>
    /// <param name="target"></param>
    void Match(IMatchTarget target);
}

第二组接口:设计过滤规则

    动态规则是需要存储到数据库中的,但是由于它的形式十分灵活,所以这里选用XML这种半结构化的数据格式来存储规则内容,最后再序列化存储到数据库中。这种解决方法适用于一些小型的、结构变化性大的对象,如下:

/// <summary>
/// 可以被序列化为XML内容的对象
/// </summary>
public interface IXmlSerializable
{
    /// <summary>
    /// 序列化为XML值。
    /// </summary>
    /// <returns></returns>
    XElement Serialize();
}
/// <summary>
/// 过滤规则
/// </summary>
public interface IFilterRule : IXmlSerializable
{
    /// <summary>
    /// 判断某个可匹配对象是否符合规则。
    /// </summary>
    /// <param name="source"></param>
    /// <returns></returns>
    bool IsMatch(IMatchable source);
}
/// <summary>
/// 对IFilterRule序列化的结果进行反序列化。
/// </summary>
public interface IFilterRuleDeserializer
{
    /// <summary>
    /// 反序列化
    /// </summary>
    /// <param name="element"></param>
    /// <returns></returns>
    IFilterRule Deserialize(XElement element);
}

    IFilterRule是这三个中最重要的接口。表示一个动态的过滤规则。在GIX4中,它可以是一个简单的规则:

“对象的Name属性应该包含***’”

    也可以是由各种简单规则复合而成,如:

“对象的Name属性应该包含***’”       AND     “对象的Name属性应该满足正则表达式***’”    AND   “对象的Amount属性应该大于0’”

    这里IFilterRule接口及其子类的设计方法,类型“表达式树”。(朋友说其实是解释器模式,不过我自己也没记住解释器模式是什么结构,所以不知道这里到底是不是。) :O)


第三组接口:元数据-比较操作

    过滤的规则是动态的,但是对于某种数据类型(string、int)进行的比较操作,却是固定的。过滤规则则是由这些固定的操作组合而成。如:我可以对User对象的Name属性(string)进行是否以某字符串开头的判断,可以定义如下:Name BeginWith “王”,这里的BeginWith就是一个比较操作,它针对类型string。操作定义如下:

/// <summary>
/// 比较操作
/// </summary>
public interface ICompareOperation
{
    /// <summary>
    /// 同类型下唯一的名字
    /// </summary>
    string Name { get; }

    /// <summary>
    /// 判断两个值是否符合这个配对策略
    /// </summary>
    /// <param name="sourceValue"></param>
    /// <param name="targetValue"></param>
    /// <returns></returns>
    bool IsMatch(object sourceValue, object targetValue);
}

第三组接口:元数据-属性规则

    由于项目中最常使用的就是根据属性的值来进行简单的过滤,所以定义了一个“可匹配属性”接口。通过它,可以获得能够对这个属性进行的所有操作。可以获取到指定的可匹配对象IMatchable的该属性值。实现时可以不使用反射而进行快速获取值,加快匹配速度。

/// <summary>
/// 用于匹配操作的属性。
/// </summary>
public interface IMatchableProperty
{
    /// <summary>
    /// 属性名
    /// </summary>
    string Name { get; }
    /// <summary>
    /// 用于显示的名字
    /// </summary>
    string Label { get; }

    /// <summary>
    /// 属性所在的IMatchable类名
    /// </summary>
    Type MatchableType { get; }
    /// <summary>
    /// 属性类型
    /// </summary>
    Type PropertyType { get; }
    /// <summary>
    /// 允许的操作
    /// </summary>
    IList<ICompareOperation> Operations { get; }

    /// <summary>
    /// 获取指定对象的值。
    /// </summary>
    /// <param name="machable"></param>
    /// <returns></returns>
    object GetValue(IMatchable machable);
}

/// <summary>
/// 匹配属性元数据工厂
/// </summary>
public interface IMatchablePropertyFactory : IStringConverter
{
    /// <summary>
    /// 根据匹配对象的类名,查询这个类所对应的用于匹配操作的所有属性。
    /// </summary>
    /// <param name="matchableTypeName"></param>
    /// <returns></returns>
    IList<IMatchableProperty> GetProperties(string matchableTypeName);
    //IList<IMatchableProperty> Get(Type matchableType);
}

    到现在,最基本的接口就已经设计完成。


集成到GIX4

1.外观

    模块使用外观模式构建Facade类来降低外部使用的复杂度。

2.组装

    系统主要是匹配PBS到FGQBQItem。本着“新增优于修改”的原则,不想在原有的类上修改或者、添加新的代码,所以这里为这两个类分别扩充新类FGQBQItemMatch和PBSMatchTarget,并实现IMatchable和IMatchTarget,然后再由实现IMatchable的类FGQBQItemMatch指定哪此属性(FGQBQItemMatchProperty类)可以用于匹配就行了,如下图:

图3 集成过程


其它-界面

    有意思的是,由于这次的界面是动态的,实现过程中使用了装饰模式以重用属性规则编辑器。图就不画了,贴下代码图:

图4 界面代码

    最后的界面如下:

图5 最终界面

其它-所有代码图

    除了界面以外,整个方案的代码图如下:

图6 所有代码


后话

    做完了,感觉解决得还行。原来发的文章都没什么人搭理,这次真心希望多来几个拍砖的,没人说,就没进步啊。嘿嘿。

    另外,cnblog没有多大的空间传文件,所以就不传代码了。如有谁需要代码,可以留言找我。

时间: 2024-10-27 10:16:09

模式应用:自定义匹配的相关文章

微信公众号开发系列-开发模式创建自定义菜单

通过程序方式实现自定义菜单,通过http请求封装类交互微信自定义菜单接口 1.得到AccessToken access_token是公众号的全局唯一票据,公众号调用各接口时都需使用access_token.正常情况下access_token有效期为7200秒,重复获取将导致上次获取的access_token失效.由于获取access_token的api调用次数非常有限,建议开发者全局存储与更新access_token,频繁刷新access_token会导致api调用受限,影响自身业务. 请开发者

Android中用Builder模式自定义Dialog的方法_Android

前言 我们开发人员在实际项目过程中遇到的需求是多种多样的,有时我们要匹配APP自己的设计风格,有时我们会觉得系统的对话框使用起来不够自由,因此自己定义一个适合自己的Dialog是很有必要的. 为什么要用Builder模式 Builder设计模式是一步步创建一个复杂对象的创建型模式,它允许用户在不知道内部构建细节的情况下,可以更精细地控制对象的构造流程.它的优点就在于将对象的构建和表示分离从而解耦.我们都知道Android系统自身的对话框如AlertDialog就采用了Builder模式,因此可见

PHP 正则表达式匹配模式学习笔记

PHP中对于正则处理文本提供了两种方式,一种是PCRE方式(PCRE库是一个实现了与perl 5在语法和语义上略有差异(详见下文)的正则表达式模式匹配功能的函数集. 当前的实现对应于perl 5.005.):另一个是POSIX方式.   PCRE函数库中的函数使用的模式语法非常类似perl. 表达式必须用分隔符闭合, 比如一个正斜杠(/). 分隔符可以使任意非字母数字, 除反斜杠()和空字节之外的非空白ascii字符. 如果分隔符 在表达式中使用, 需要使用反斜线进行转义. 自php 4.0.4

正则表达式惰性匹配模式(?)

正则表达式惰性匹配模式: 在贪婪匹配模式一章节已经说过人性是贪婪的,希望获得更多的金钱.地位甚至美女,但是也有很多清心寡欲的人,只要满足基本的生活需求就可以了,在正则表达式中也有这样的匹配原则,下面就进行一下介绍. 一.惰性模式的概念: 此模式和贪婪模式恰好相反,它尽可能少的匹配字符以满足正则表达式即可,例如: var str="axxyyzbdkb"; console.log(str.match(/a.*b/)); 以上代码是贪婪模式,于是能够匹配整个字符串,下面将其修改成惰性匹配模

JiBX 1.2,第2部分: 从XML模式到Java代码(一)

通过 XML 模式生成更干净的自定义 Java 代码 通过 XML 模式定义生成代码被广泛用于各种类型的 XML 数据交换,包括 Web 服务在内.大多数数据绑定工具都是根据模式严格地组织生成的代码 - 甚至根据可能与应用程序不相关的模式方面.本教程是共两部分的 系列教程 的第二部分,将介绍 JiBX 1.2 如何通过更好地解析模式和消除不必要的类混乱来生成更干净的代码.您还将看到如何自定义生成的代码以更好地满足需求,包括轻松地消除不必要的模式组件的自定义. 开始之前 关于本教程 JiBX 是

JiBX 1.2,第1部分: 从Java代码到XML模式

通过 Java 数据模型与 XML 文档之间的自定义转换提高模式质量 XML 模式定义是许多数据交换类型(包括大多数 Web 服务形式)的基础.但是 XML Schema 是一种十分复杂的标准,并且与处理 Java 代码的工具相比,用于创建和修改模式定义的大多数工具在功能性和易用性方面要逊色一些.您将在本教程 - 共两部分的 系列教程 的第 1 部分 - 中了解到 JiBX 1.2 的新功能,它将允许您从 Java 代码入手并轻松地生成优秀的模式定义来匹配数据结构.然后,无论您是否使用 JiBX

微信公众号开发之自定义菜单

微信开发交流群:148540125 系列文章参考地址 极速开发微信公众号 欢迎留言.转发 项目源码参考地址 点我点我–欢迎Start 前几篇文章已讲完如何导入项目,如何启动配置项目,如何成为开发者,重源码分析消息是如何交互(如果前四项不是很清楚可以看这里 极速开发微信公众号.这篇文章就来讲讲如果实现自定义菜单 实现自定义菜单有两种方式 1.编辑模式 2.开发模式 编辑模式就很简单了就不赘述了-- 开发模式实现自定义菜单 1.使用微信公众平台接口调试工具实现 2.使用官方提供的接口实现 前期准备

深入XSL(3)---模板规则和模式(转)

模板   深入XSL(3)---模板规则和模式翻译:孙一中  模板规则 模板规则由xsl:template元素来规定."match"属性标识了规则应用的源节点(集).xsl:template. 例如:一个XML文档可能包含下面的内容: This is an <emph>important</emph> point. 下列的模板规则匹配emph类型的元素,另有一个模板产生一fo:sequence 格式化对象,其font-weight属性为粗体(bold). <

Javascript教程:组合使用构造函数模式和原型模式

文章简介:创建自定义类型的常见方式,就是组合使用构造函数模式与原型模式.构造函数模式用于定义实例属性,而原型模式用于定义方法和共享的属性.结果,每个实例都会有自己的一份实例属性的副本.但同时又共享着对方法的引用,最大限度的节省了内存.另外这种模式还支持向构造函 创建自定义类型的常见方式,就是组合使用构造函数模式与原型模式.构造函数模式用于定义实例属性,而原型模式用于定义方法和共享的属性.结果,每个实例都会有自己的一份实例属性的副本.但同时又共享着对方法的引用,最大限度的节省了内存.另外这种模式还