65.9K
CodeProject 正在变化。 阅读更多。
Home

收集器、转换器和格式化器模式

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.40/5 (7投票s)

2016年2月3日

CPOL

6分钟阅读

viewsIcon

26883

downloadIcon

310

收集器、转换器和格式化器模式初学者指南

引言

本文将向大家介绍收集器、转换器和格式化器模式。在深入探讨该模式之前,我假设目标读者对实现标准设计模式有一些经验。此外,对面向对象原则和实践有透彻的理解。

如果你有兴趣学习和实现一种机制来收集数据、应用转换器来修改内容以及应用格式化器来格式化数据,那么你就是本文的合适读者。众所周知,设计模式是解决常见重复问题的方案。今天,我们将解决数据收集、转换和格式化最常见的实践。真实世界场景

让我们通过一个例子来理解真实世界的场景。

  1. 考虑一个`DateTime`对象的例子。它保存实际的`DateTime`值,但当涉及到`DateTime`的格式化时,例如你可能通过指定格式字符串、`IFormatProvider`或它们的组合来使用`DateTime`的`ToString`方法以返回特定格式的日期。在内部,`DateTime`类的`ToString`方法使用一个名为“`DateTimeFormat`”的内部类来格式化`DateTime`值。请查看http://www.dotnetperls.com/datetime-format以了解`DateTime`格式化。
     
  2. 以医疗保健信息交换(HIE)产品为例,你希望以可互操作的方式传输或交换患者的医疗保健信息。这意味着,你希望以特定格式(如CCR、CCD、CDA和FHIR等)导出患者数据。想象一下,你有一个数据库,其中存储了所有患者、提供者和相关的患者健康信息。在这种情况下,数据的消费者不受特定数据格式的约束,而是根据行业指定格式接受患者健康信息。

    负责交换健康信息的软件应该能够支持客户的需求。这时就需要数据收集器和格式化器。数据库是存储患者数据的介质。可以根据客户需求收集、转换和转换数据。

设计模式的高级概述

注意:以下格式化程序类型仅用于演示目的。

收集器

“`收集器`”是一个负责收集数据的实体。你的数据可能存储在平面文件、数据库或任何格式中。最终,收集器的作用是收集这些数据。定义清晰的边界上下文很重要。收集器看起来像数据访问组件。在某些情况下,它可能不是。因此,最好将收集器与数据访问组件分开。

转换器

“`转换器`”是一个负责修改或更改收集器收集的数据的实体。该实体负责处理收集到的数据。有时你需要根据客户要求执行翻译或应用通用翻译。所有通用和客户端特定的翻译规则都应作为转换器。你不需要为每个收集器都使用转换器。注意 - 转换器是可选实体。它取决于你所处理的领域。

Formatter

“`格式化器`”是一个负责格式化收集器收集的数据或转换后的数据的实体。“格式化器”根据客户需求将数据转换为特定格式。格式化器的一个例子是将收集器收集的数据转换为JSON或XML格式。

解耦收集器、转换器和格式化器的必要性

让我们试着理解解耦收集器、转换器和格式化器的需求或必要性。我们将实现以下目标。

松耦合,并具有收集、翻译和格式化数据的单一职责。

  • 有时,在处理数据转换时。将它们分开始终是个好主意。这时就出现了“`转换器`”的作用。
  • 格式化器不必依赖收集器。这意味着收集器和格式化器可以共存,并且可以独立修改,而互不影响。
  • 依赖性越小,越容易增强或扩展收集器、转换器或格式化器的现有行为。你可以自由地扩展格式化器以支持额外的客户端需求。

背景

对标准设计模式的了解和理解。

使用代码

让我们看一下示例代码,了解如何实现该模式。出于演示目的,我将以Open Dental中自定义的健康级别7(HL7)消息为例。在收集器中,我们将收集一个包含“`Message`”实体的HL7消息对象。此外,“`Message`”实体由“`MessageHeader`”、“`PatientIdentification`”、“`Guarantor`”和“`Insurance`”实体组成。

public class HL7MessageRoot  
{  
    public MessageMessage  
    {  
        get;  
        set;  
    }  
}  
  
public classMessage  
{  
    public MessageHeaderMessageHeader  
    {  
        get;  
        set;  
    }  
    public PatientIdentificationPatientIdentification   
    {  
        get;  
        set;  
    }  
    public GuarantorGuarantor  
    {  
        get;  
        set;  
    }  
    public InsuranceInsurance   
    {  
        get;  
        set;  
    }  
}  

出于演示目的,我们不会访问数据库并构建HL7消息对象。相反,我们将返回一个模拟对象。下面是其高级代码片段。

public classMockHL7Message   
{  
    public HL7MessageRoot GetHL7Message()   
    {  
        return new HL7MessageRoot   
        {  
            Message = GetMessage()  
        };  
    }  
  
    MessageGetMessage()  
    {  
            return newMessage   
            {  
                MessageHeader = GetMessageHeader(),  
                    PatientIdentification = GetPatientIdentification(),  
                    Guarantor = GetGuarantor(),  
                    Insurance = GetInsurance()  
            };  
        }  
        .  
        .  
        .  
}  

这是我们收集器的代码片段。

public class HL7MessageCollector  
{  
    public HL7MessageRoot Collect()   
    {  
        // Return Mock Data for now  
        return new MockHL7Message().GetHL7Message();  
    }  
}  

现在让我们讨论“`转换器`”。我们将有两个。一个用于格式化电话号码,另一个用于屏蔽SSN号码。下面是其代码片段。

public class PhoneNumberTranslator: ITranslate  
{  
        public string Translate(stringphoneNumber)  
        {  
            return phoneNumber.ToString()  
                .Replace("-", "")  
                .Replace("(", "")  
                .Replace(")", "");  
        }  
}  

//Reused code - http://stackoverflow.com/questions/5254197/format-ssn-using-regex  
public class SSNMaskTranslator: ITranslate   
{  
    publicstring Translate(stringoriginalSSN)   
    {  
        string ssn = originalSSN.ToString();  
        if (ssn.Length < 5) originalSSN = ssn;  
        var trailingNumbers = ssn.Substring(ssn.Length - 4);  
        var leadingNumbers = ssn.Substring(0, ssn.Length - 4);  
        var maskedLeadingNumbers = Regex.Replace(leadingNumbers, @ "[0-9]", "X");  
        return maskedLeadingNumbers + trailingNumbers;  
    }  
}  

现在我们解决方案的最后一个重要部分是格式化器。作为演示示例的一部分,我们将有两种格式化器。一种用于将HL7消息格式化为XML,另一种用于JSON。下面是`HL7JsonFormatter`的代码片段,我们利用JSON.NET来序列化HL7消息对象。为了在控制台上显示JSON输出,我使用了可选参数Formatting.Indented。

public class HL7JsonFormatter: IHL7Formatter  
{  
    public string FormatHL7Message(HL7MessageRoot hL7MessageRoot)  
    {  
        return JsonConvert.SerializeObject(hL7MessageRoot, Formatting.Indented);  
    }  
}  

下面是`HL7XMLFormatter`的代码片段。“`FormatHL7Message`”方法接受一个HL7消息根对象,并负责通过创建XML文档并为“`MessageHeader`”、“`PatientIdentification`”、“`Gaurantor`”和“`Insurance`”添加XML元素来构建基于XML的HL7消息。

public class HL7XMLFormatter: IHL7Formatter   
{  
    public string FormatHL7Message(HL7MessageRoot hL7MessageRoot)  
    {  
        XDocumentxDocument = new XDocument();  
        var messageElement = new XElement("Message");  
  
        messageElement.Add(GetMessageHeader(hL7MessageRoot));  
        messageElement.Add(GetPatientIdentification(hL7MessageRoot));  
        messageElement.Add(GetGuarantor(hL7MessageRoot));  
        messageElement.Add(GetInsurance(hL7MessageRoot));  
        xDocument.Add(messageElement);  
  
        StringBuilderstringBuilder = new StringBuilder();  
        using(TextWriter writer = new StringWriter(stringBuilder))  
        {  
            xDocument.Save(writer);  
        }  
  
        returnstringBuilder.ToString();  
    }  
  
    XElementGetMessageHeader(HL7MessageRoot hL7MessageRoot)  
    {  
        return new XElement("MessageHeader",  
            new XElement("DateTimeOfMessage",  
                hL7MessageRoot.Message.MessageHeader.DateTimeOfMessage),  
            new XElement("MessageType",  
                hL7MessageRoot.Message.MessageHeader.MessageType),  
            new XElement("OpenDentalVersion",  
                hL7MessageRoot.Message.MessageHeader.OpenDentalVersion));  
    }  
  
    XElementGetPatientIdentification(HL7MessageRoot hL7MessageRoot)  
    {  
        return new XElement("PatientIdentification",  
            newXElement("NameLast",  
                hL7MessageRoot.Message.PatientIdentification.NameLast),  
            newXElement("NameFirst",  
                hL7MessageRoot.Message.PatientIdentification.NameFirst),  
            newXElement("NameMiddle",  
                hL7MessageRoot.Message.PatientIdentification.NameMiddle),  
            newXElement("DateOfBirth",  
                hL7MessageRoot.Message.PatientIdentification.DateOfBirth),  
            newXElement("Sex",  
                hL7MessageRoot.Message.PatientIdentification.Sex),  
            newXElement("AliasFirst",  
                hL7MessageRoot.Message.PatientIdentification.AliasFirst),  
            newXElement("AddressStreet",  
                hL7MessageRoot.Message.PatientIdentification.AddressStreet),  
            newXElement("AddressOtherDesignation",  
                hL7MessageRoot.Message.PatientIdentification.AddressOtherDesignation),  
            newXElement("AddressCity",  
                hL7MessageRoot.Message.PatientIdentification.AddressCity),  
            newXElement("AddressStateOrProvince",  
                hL7MessageRoot.Message.PatientIdentification.AddressStateOrProvince),  
            newXElement("AddressZipOrPostalCode",  
                hL7MessageRoot.Message.PatientIdentification.AddressZipOrPostalCode),  
            newXElement("PhoneHome",  
                hL7MessageRoot.Message.PatientIdentification.PhoneHome),  
            newXElement("EmailAddressHome",  
                hL7MessageRoot.Message.PatientIdentification.EmailAddressHome),  
            newXElement("PhoneBusiness",  
                hL7MessageRoot.Message.PatientIdentification.PhoneBusiness),  
            newXElement("MaritalStatus",  
                hL7MessageRoot.Message.PatientIdentification.MaritalStatus),  
            newXElement("SSN",  
                hL7MessageRoot.Message.PatientIdentification.SSN),  
            newXElement("NotePhoneAddress",  
                hL7MessageRoot.Message.PatientIdentification.NotePhoneAddress),  
            newXElement("NoteMedicalComplete", 
                hL7MessageRoot.Message.PatientIdentification.NoteMedicalComplete));  
    }  
  
    XElementGetGuarantor(HL7MessageRoot hL7MessageRoot)  
    {  
        returnnewXElement("Guarantor",  
            newXElement("NameLast",  
                hL7MessageRoot.Message.Guarantor.NameLast),  
            newXElement("NameFirst",  
                hL7MessageRoot.Message.Guarantor.NameFirst),  
            newXElement("NameMiddle",  
                hL7MessageRoot.Message.Guarantor.NameMiddle),  
            newXElement("AddressStreet",  
                hL7MessageRoot.Message.Guarantor.AddressStreet),  
            newXElement("AddressOtherDesignation",  
                hL7MessageRoot.Message.Guarantor.AddressOtherDesignation),  
            newXElement("AddressCity",  
                hL7MessageRoot.Message.Guarantor.AddressCity),  
            newXElement("AddressStateOrProvince",  
                hL7MessageRoot.Message.Guarantor.AddressStateOrProvince),  
            newXElement("AddressZipOrPostalCode",  
                hL7MessageRoot.Message.Guarantor.AddressZipOrPostalCode),  
            newXElement("PhoneHome",  
                hL7MessageRoot.Message.Guarantor.PhoneHome),  
            newXElement("EmailAddressHome",  
                hL7MessageRoot.Message.Guarantor.EmailAddressHome),  
            newXElement("PhoneBusiness",  
                hL7MessageRoot.Message.Guarantor.PhoneBusiness),  
            newXElement("DateOfBirth",  
                hL7MessageRoot.Message.Guarantor.DateOfBirth),  
            newXElement("Sex",  
                hL7MessageRoot.Message.Guarantor.Sex),  
            newXElement("GuarantorRelationship",  
                hL7MessageRoot.Message.Guarantor.GuarantorRelationship),  
            newXElement("SSN",  
                hL7MessageRoot.Message.Guarantor.SSN),  
            newXElement("EmployerName",  
                hL7MessageRoot.Message.Guarantor.EmployerName),  
            newXElement("MaritalStatus",  
                hL7MessageRoot.Message.Guarantor.MaritalStatus));  
    }  
  
    XElementGetInsurance(HL7MessageRoot hL7MessageRoot)  
    {  
        returnnewXElement("Insurance",  
            newXElement("CompanyName",  
                hL7MessageRoot.Message.Insurance.CompanyName),  
            newXElement("AddressStreet",  
                hL7MessageRoot.Message.Insurance.AddressStreet),  
            newXElement("AddressOtherDesignation",  
                hL7MessageRoot.Message.Insurance.AddressOtherDesignation),  
            newXElement("AddressCity",  
                hL7MessageRoot.Message.Insurance.AddressCity),  
            newXElement("AddressStateOrProvince",  
                hL7MessageRoot.Message.Insurance.AddressStateOrProvince),  
            newXElement("AddressZipOrPostalCode",  
                hL7MessageRoot.Message.Insurance.AddressZipOrPostalCode),  
            newXElement("PhoneNumber",  
                hL7MessageRoot.Message.Insurance.PhoneNumber),  
            newXElement("GroupNumber",  
                hL7MessageRoot.Message.Insurance.GroupNumber),  
            newXElement("GroupName",  
                hL7MessageRoot.Message.Insurance.GroupName),  
            newXElement("InsuredGroupEmpName",  
                hL7MessageRoot.Message.Insurance.InsuredGroupEmpName),  
            newXElement("PlanEffectiveDate",  
                hL7MessageRoot.Message.Insurance.PlanEffectiveDate),  
            newXElement("PlanExpirationDate",  
                hL7MessageRoot.Message.Insurance.PlanExpirationDate),  
            newXElement("InsuredsNameLast",  
                hL7MessageRoot.Message.Insurance.InsuredsNameLast),  
            newXElement("InsuredsNameFirst",  
                hL7MessageRoot.Message.Insurance.InsuredsNameFirst),  
            newXElement("InsuredsNameMiddle",  
                hL7MessageRoot.Message.Insurance.InsuredsNameMiddle),  
            newXElement("InsuredsRelationToPat",  
                hL7MessageRoot.Message.Insurance.InsuredsRelationToPat),  
            newXElement("InsuredsDateOfBirth",  
                hL7MessageRoot.Message.Insurance.InsuredsDateOfBirth),  
            newXElement("InsuredsAddressStreet",  
                hL7MessageRoot.Message.Insurance.InsuredsAddressStreet),  
            newXElement("InsuredsAddressOtherDesignation",  
                hL7MessageRoot.Message.Insurance.InsuredsAddressOtherDesignation),  
            newXElement("InsuredsAddressCity",  
                hL7MessageRoot.Message.Insurance.InsuredsAddressCity),  
            newXElement("InsuredsAddressStateOrProvince",  
                hL7MessageRoot.Message.Insurance.InsuredsAddressStateOrProvince),  
            newXElement("InsuredsAddressZipOrPostalCode",  
                hL7MessageRoot.Message.Insurance.InsuredsAddressZipOrPostalCode),  
            newXElement("AssignmentOfBenefits",  
                hL7MessageRoot.Message.Insurance.AssignmentOfBenefits),  
            newXElement("ReleaseInformationCode",  
                hL7MessageRoot.Message.Insurance.ReleaseInformationCode),  
            newXElement("PolicyNumber",  
                hL7MessageRoot.Message.Insurance.PolicyNumber),  
            newXElement("PolicyDeductible",  
                hL7MessageRoot.Message.Insurance.PolicyDeductible),  
            newXElement("PolicyLimitAmount",  
                hL7MessageRoot.Message.Insurance.PolicyLimitAmount),  
            newXElement("InsuredsSex",  
                hL7MessageRoot.Message.Insurance.InsuredsSex),  
            newXElement("InsuredsSSN",  
                hL7MessageRoot.Message.Insurance.InsuredsSSN),  
            newXElement("InsuredsPhoneHome",  
                hL7MessageRoot.Message.Insurance.InsuredsPhoneHome),  
            newXElement("NotePlan",  
                hL7MessageRoot.Message.Insurance.NotePlan));  
    }  
}  

这是`HL7MessageFormatter`的代码片段,它接受`HL7MessageRoot`对象并根据指定的格式化程序格式化为HL7消息。

public class HL7MessageFormatter   
{  
    HL7MessageRoot hL7MessageRootObject;  
  
    public HL7MessageFormatter(HL7MessageRoot hL7MessageRoot)  
    {  
        hL7MessageRootObject = hL7MessageRoot;  
    }  
  
    public string Format(IHL7Formatter formatter)  
    {  
        return formatter.FormatHL7Message(hL7MessageRootObject);  
    }  
}  

让我们看一下主代码,看看如何连接收集器、转换器和格式化器。下面是相同的代码片段。首先我们收集数据,然后我们将转换电话号码、SSN掩码等。最后,我们通过使用我们构建的格式化器来调用将HL7消息对象格式化为XML和JSON。

static void Main(string[] args)  
{  
    // Collect or Gather Data  
    var hL7MessageCollector = newHL7MessageCollector();  
    var hL7MessageRoot = hL7MessageCollector.Collect();  
    
    // Translate data  
    Translate(hL7MessageRoot);  
  
    // Format and display as XML  
    Console.WriteLine("Display HL7 message as XML\n");  
    varxmlOutput = FormatToXML(hL7MessageRoot);  
    Console.WriteLine(xmlOutput);  
  
    // Format and display as JSON  
    Console.WriteLine("\nDisplay HL7 message as JSON\n");  
    varjsonOutput = FormatToJSON(hL7MessageRoot);  
    Console.WriteLine(jsonOutput);  
  
    Console.ReadLine();  
}  

这是格式化 HL7 消息对象的代码片段。

static stringFormatToXML(HL7MessageRoot hL7MessageRoot)  
{  
    var hL7MessageFormatter = newHL7MessageFormatter(hL7MessageRoot);  
    return hL7MessageFormatter.Format(newHL7XMLFormatter());  
}  
  
static stringFormatToJSON(HL7MessageRoot hL7MessageRoot)  
{  
    var hL7JSONFormatter = newHL7MessageFormatter(hL7MessageRoot);  
    return hL7JSONFormatter.Format(newHL7JsonFormatter());  
}  

下面是“`转换器`”的代码片段,我们利用`PhoneNumberTranslator`通过移除连字符和括号来翻译或更改电话号码。`SSNMaskTranslator`用于掩码SSN号码。

static void Translate(HL7MessageRoot hL7MessageRoot)  
{  
    var phoneNumber = hL7MessageRoot.Message.PatientIdentification.PhoneHome;  
    var phoneNumberTranslator = newPhoneNumberTranslator();  
  
    if (!string.IsNullOrEmpty(phoneNumber))   
    {  
        hL7MessageRoot.Message.PatientIdentification.PhoneHome = 
               phoneNumberTranslator.Translate(phoneNumber);  
    }  
  
    var ssn = hL7MessageRoot.Message.PatientIdentification.SSN;  
    var ssnMaskTranslator = newSSNMaskTranslator();  
  
    if (!string.IsNullOrEmpty(ssn))  
    {  
        hL7MessageRoot.Message.PatientIdentification.SSN = ssnMaskTranslator.Translate(ssn);  
    }  
  
    ssn = hL7MessageRoot.Message.Guarantor.SSN;  
    if (!string.IsNullOrEmpty(ssn))  
    {  
        hL7MessageRoot.Message.Guarantor.SSN = ssnMaskTranslator.Translate(ssn);  
    }  
}  

HL7 模型类图

转换器类图

下面是转换器类的类图。

注意: 以下类是示例应用程序的一部分,转换器是可选的,纯粹取决于您正在处理的领域。

格式化器类图

HL7 消息(XML 格式)

这是HL7消息如何格式化为XML的屏幕截图。

HL7 消息(JSON 格式)

这是HL7消息如何格式化为JSON的屏幕截图。

关注点

尽管这只是尝试创建解决特定类型问题设计模式的一小步,但我很高兴分享我长期以来的想法。我真的很兴奋:)

欢迎开放和建设性的批评!

最新代码也可在 - https://github.com/ranjancse26/CollectorFormatterSample 找到

历史

版本 1.0 - 初稿于 2015 年 3 月 2 日发布到 CP。

© . All rights reserved.