代理商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示例中,数据是相同的,但格式不同,这导致一些人将所有不同格式映射到一组公共类,但是不仅仅是格式不同,但数据也不同?
答案 0 :(得分: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...
}
}
答案 1 :(得分: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
}
如果它们的实现完全不同,您可以使用接口
答案 2 :(得分: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.
}
}
答案 3 :(得分:0)
一种可能的方法是创建一个抽象基类代理,您将在其中保存公共数据。这个类有一个名为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()的接口。对于每个代理商,您都会继承您的界面并为该代理商格式编写特定的解析。
答案 4 :(得分: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
当然,把所有其他字段/获取/设置方法放在上面。
答案 5 :(得分:0)
通过创建BaseAgencyClass和/或AbstractAgencyClass和/或IAgency接口,您只需准备自己制作单个Agency功能的多个实现(这是您想要避免的)。基本类和抽象类和接口在正确使用时非常合适,但它们无法解决您想要做的事情。相反,用解析器解决问题。
创建单个类[Agency](并使用适合您的解决方案的接口和/或基类)以及针对所有代理的单个通用解析器。您希望尽快将各种格式的XML转换为常见的Agency对象。不要将XML中的差异持久保存到您的代理商实施中。
对于你的解析器(它可能是代理上的方法,或内置到Agency的构造函数,或负责解析的其他对象,无论如何),只需以动态方式解析XML。所有XML都只是一系列PARENT / CHILD关系。使用XML,总有一个ROOT元素,因此您始终可以从ELEMENT开始。然后找到应该是下一个的孩子,首先检查ELEMENT的属性。如果找不到,请检查ELEMENT的CHILDREN(嵌套元素)。如果你没有找到它,那么检查ELEMENT的值(ELEMENT中保存的文本)。
您应该能够以这种方式咀嚼XML,并将所有组合解析为COMMON Agency Object。无需代码重复或多个实现。祝你好运!
修改强> 这是编写“通用解析器”的示例。这不是生产代码,而只是使用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;
}
例如,这只会解析“取件日期”并将其填充到单一的Agency对象中。它处理了可以找到“提取日期”的3种情况。就像我说的,这不是生产代码所以你想要以更安全和更合适的方式编写它。例如,XML区分大小写,因此在解析之前将XML转换为所有UPPER或LOWER(如果可能)可能是个好主意。或者您也可以使用正则表达式转换ELEMENT&amp; ATTRIBUTE命名为UPPER但不影响实际值,如果这很重要的话。
如果您所说的是数据可能是完全未知的 XML布局,那么这可能无效。但这至少可以解决您的已知布局,而有效的XML只能以这么多方式排列!希望这有帮助!