1

我有 3 家汽车租赁公司。每个机构都需要 XML 格式的数据,但格式不同,例如:

机构 1

<Rental>
<Customer>
<FirstName>test</FirstName>
<LastName>test</LastName>
</Customer>
<Pickup date="07/20/2012"/>
<Dropoff date="07/25/2012"/>
<Deposit cost="100"/>
</Rental>

机构 2

<Rental>
<Customer>
<FirstName>test</FirstName>
<LastName>test</LastName>
</Customer>
<Pickup>07/20/2012</Pickup>
<Dropoff>07/25/2012</Dropoff>
<Deposit>100</Deposit>
</Rental>

机构 3

<Rental pickup="07/20/2012" dropoff="07/25/2012" deposit="100">
<Customer>
<FirstName>test</FirstName>
<LastName>test</LastName>
</Customer>
</Rental>

正如你从上面看到的,所有 3 个基本上都包含相同的信息,尽管不一定是这种情况(有些可能包含或多或少的信息),但它的结构不同,所以我访问它的方式不同。最好的方法是什么,以便我可以编写最少的代码,但能够适应具有不同结构的新租赁机构?

现在,我正在做这样的事情:

public class Agency1
{
SubmitRental()
{
//Parse XML for Agency 1
}

//Other methods for agency 1
}

public class Agency2
{
SubmitRental()
{
//Parse XML for Agency 2
}

 //Other methods for agency 2
}

public class Agency3
{
SubmitRental()
{
//Parse XML for Agency 3
}

//Other methods for agency 3
}

在上面,类包含相同的方法,但它们的实现方式不同。有些类中有一些方法、属性等,而另一些类中没有。接口是解决这个问题的最佳方法吗?如果是这样,是否应该将所有内容都设为接口?

在上面的 XML 示例中,数据是相同的,但格式不同,这导致一些人提出将所有不同的格式映射到一组通用类,但是不只是格式不同的场景呢,但数据也不同?

4

6 回答 6

4

我通常会将解析与数据表示分开,例如:

public class Rental
{
    public string CustomerFirstName { get; set; }
    public DateTime Pickup { get; set; }
    // ... etc ...
}

和一组数据解析器:

public interface IAgencyRentalParser
{
    XmlDocument ToXml(Rental rental);
    Rental FromXml(XmlDocument xml);
}

public class Agency1RentalParser : IAgencyRentalParser { ... }

public class Agency2RentalParser : IAgencyRentalParser { ... }

public class Agency3RentalParser : IAgencyRentalParser { ... }

以及其他一些用于确定使用哪个解析器的机制。就像返回适当解析器的工厂模式一样......

public class AgencyRentalParserFactory
{
    public IAgencyRentalParser GetParserFor(XmlDocument xml)
    {
        // create and return one of the parsers...
    }
}
于 2012-07-16T19:39:44.067 回答
1

继承和多态

public class Agency
{
    public virtual void SubmitRental()
    {
        //can leave empty, or provide default behavior
    }

    // methods and properties/fields common to all Agencies.  
}

public class Agency1 : Agency
{
    public override void SubmitRental()
    {
        //insert submit logic here
    }
    //methods and properties/fields specific to Agency1
}

如果它们的实现方式完全不同,您可以使用接口

http://msdn.microsoft.com/en-us/library/ms173156.aspx

于 2012-07-16T19:36:04.413 回答
0

只需创建一个基本抽象类,它将包含每个机构通用的所有信息和标记为虚拟的所有方法。而不是为每个机构创建具体的课程。

public abstract class AgencyBase
{
    private string _customer;
    // other fields that every agency have.

    public abstract void SubmitRental();

//Other methods for agency
}

public class Agency1 : AgencyBase
{
    // Agency specific fields.

    public override void SubmitRental()
    {
        // Your implementation.
    }
}
于 2012-07-16T19:39:20.070 回答
0

一种可能的方法是创建一个抽象基类 Agency,您将在其中保存公共数据。此类有一个名为 submitRental() 的抽象方法,例如:

public abstract class Agency {
  public abstract void SubmitRental();

  //Other methods for agency ...
}

public class AgencyOne : Agency {
  public void SubmitRental() {
    // agency one specific code...
  }
}

另一种方法是创建一个接口,其中包含方法 SubmitRental()。对于每个代理,您继承您的接口并为该代理格式编写特定的解析。

于 2012-07-16T19:40:18.277 回答
0

如果我是设计它的人,那么我会以简单的方式看待它:

1) 代理对象:

ID (string to identify 'Agency 1','Agency 2' and so on.)
Customer (Reference to Person Object)
Shipping (Reference to Shipping Object)

SubmitRental 方法 - 应包含基于 ID 字段和其他数据的自定义

2)人对象:

FirstName
LastName

3) 出租对象:

Pickup Date
Dropoff Date
Deposit

当然,把你可以放在上面的所有其他字段/获取/设置方法放在上面。

于 2012-07-16T19:40:55.707 回答
0

通过创建 BaseAgencyClass 和/或 AbstractAgencyClass 和/或 IAgency 接口,您只是在准备自己进行单个代理功能的多个实现(这是您想要避免的)。如果使用得当,基类和抽象类和接口 [非常] 合适,但它们不会解决您想要做的事情。相反,请使用解析器解决问题。

为所有代理创建一个类 [Agency](如果适合您的解决方案,请使用接口和/或基类)和一个通用解析器。您希望尽快将各种格式的 XML 放入一个通用的 Agency 对象中。不要将 XML 的差异保留到您的代理实现中。

对于您的解析器(它可以是 Agency 上的一个方法,或者内置于 Agency 的构造函数中,或者其他负责解析的对象,等等),只需以动态方式解析 XML。所有的 XML 只是一系列 PARENT/CHILD 关系。对于 XML,总有一个 ROOT 元素,因此您总是可以从 ELEMENT 开始。然后要找到应该是下一个的孩子,首先检查元素的属性。如果找不到,请检查 ELEMENT 的 CHILDREN(嵌套元素)。如果你没有找到它,那么检查 ELEMENT 的 VALUE(包含在 ELEMENT 中的文本)。

您应该能够以这种方式仔细阅读您的 XML,并将所有组合解析为一个 COMMON 代理对象。无需重复代码或多次实现。祝你好运!

编辑: 这是编写“通用解析器”的示例。这不是生产代码,而只是使用您的 3 个 XML 示例的快速而肮脏的示例:

class Program
{
    static void Main(string[] args)
    {
        IList<XDocument> xmls = new List<XDocument>()
                                    {
                                        XDocument.Load("XMLFile1.xml"),
                                        XDocument.Load("XMLFile2.xml"),
                                        XDocument.Load("XMLFile3.xml")
                                    };
        Agency agency = new Agency();

        foreach (var xml in xmls)
        {
            var rental = new Rental();
            #region Pickup Date
            if (xml.Root.Attribute("pickup") != null)
                rental.Pickup = DateTime.Parse(xml.Root.Attribute("pickup").Value);
            else if (xml.Root.Element("Pickup") != null)
            {
                var pickupElement = xml.Root.Element("Pickup");
                rental.Pickup = DateTime.Parse(pickupElement.Attribute("date") != null ? pickupElement.Attribute("date").Value : pickupElement.Value);
            }
            // else there's no pickup date defined
            #endregion
            agency.rentals.Add(rental);
        }
    }
}

public class Agency
{
    public IList<Rental> rentals = new List<Rental>();
}

public class Rental
{
    public DateTime Pickup;
}

例如,这只解析出“提货日期”并将其填充到单个代理对象中。它处理可能会出现“提货日期”的 3 种情况。就像我说的,这不是生产代码,因此您希望以更安全、更合适的方式编写它。例如,XML 区分大小写,因此在解析之前将您的 XML 转换为全部 UPPER 或 LOWER(如果可能)可能是个好主意。或者,如果这很重要,您也可以使用 Regex 仅将 ELEMENT & ATTRIBUTE 名称转换为 UPPER 但不影响实际值。

如果您所说的是数据可能以完全未知的XML 布局出现,那么这可能行不通。但这至少可以解决您已知的布局,而有效的 XML 只能以多种方式排列!希望这可以帮助!

于 2012-07-16T20:24:52.480 回答