如何在以下场景中使用面向对象的原则?

时间:2012-07-16 19:29:33

标签: c# oop

我有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示例中,数据是相同的,但格式不同,这导致一些人将所有不同格式映射到一组公共类,但是不仅仅是格式不同,但数据也不同?

6 个答案:

答案 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
}

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

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

答案 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只能以这么多方式排列!希望这有帮助!