3
\$\begingroup\$

I have 3 car rental agencies. Each agency requires the data in XML, but in a different format, for example:

Agency 1

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

Agency 2

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

Agency 3

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

As you can see from above, all 3 basically contain the same information, altough this doesn't have to be the case (some can contain more or less information), but it is structured different, so the way I access it is different. What is the best approach to take so I can write the most minimum code, but be able to adapt to new rental agencies that come along with a different structure?

Right now, I am doing something like this:

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
}

In the above, the classes contain the same methods, but the way they are implemented is different. There are some methods, properties, etc that are in some classes, but not in others. Are interfaces the best way to approach this? If so, should everything be made an interface?

In the XML samples above, the data was the same, but the format was different, which led some to bring up mapping the all the different formats to a set of common classes, but what about the scenario where not only is the format different, but the data is different as well?

For example:

Agency 4

<Rental start="07/20/12" end="07/25/12">
<Name>John Doe</Name>
<DriverLicenseNumber>193048204820</DriverLicenseNumber>
<DOB>3/4/64</DOB>
<Rental>
\$\endgroup\$
1
  • \$\begingroup\$ There's a date/time type in XML, which should at least help some with stuff in respect to that datatype. I wouldn't be surprised if there's a money-related one too. \$\endgroup\$ Jul 17, 2012 at 21:02

2 Answers 2

3
\$\begingroup\$

Assuming all three companies require the same information, create a base class "CarRentalInformation." This information will store/transmit all pertinent information.

Create serializer/deserializer classes for all types of can rentals you need. You could probably use the factory pattern effectively here even if you need specialized information for each type you need.

The logic could then be written as

public List<CarRentalInformation> GetCarRentalInformation(string XML)
{
   CarRentalXmlType xmlType = this.DetectCarRentalXmlFormat(XML);
   ICarRentalFactory deserializer = this.GetCarRentalFactory(xmlType);

   return deserializer.Deserialize(XML);
}

public string GetCarRentalXML(List<CarRentalInformation> rentalInfo, CarRentalXmlType xmlType)
{
   ICarRentalFactory serializer = this.GetCarRentalFactory(xmlType);
   return serializer.Serialize(rentalInfo);
}

private CarRentalXmlType DetectCarRentalXmlFormat(string XML)
{
   //do some magic detectivework, and return appropriate type
   return CarRentalXmlType.Budget;
}

private ICarRentalFactory GetCarRentalFactory(CarRentalXmlType xmlType)
{
   switch(xmlType)
   {
       case CarRentalXmlType.Budget:
          return new BudgetCarRentalFactory();
       case CarRentalXmlType.Dollar:
          return new DollarCarRentalFactory();
       default
          return null;
    }
}

public interface ICarRentalFactory
{
    public List<CarRentalInformation> Deserialize(string XML);
    public string Serialize(List<CarRentalInformation> rentalInfo);
}

public class BudgetCarRentalFacotry : ICarRentalFactory
{
   //contains code to serialize/deserialize XML into CarRentalInformation objects
}
\$\endgroup\$
7
  • \$\begingroup\$ In my example, all the agencies had the same data, but in most cases, the data will be different(some will have more and some will have less and some may call the elements/attributes something else) and it will be in different formats, so does this rule having some a mapping class out or is it still plausible? \$\endgroup\$
    – Xaisoft
    Jul 16, 2012 at 20:18
  • \$\begingroup\$ This would definitely make a candidate for a builder pattern with dependency injection, as you could use one central engine to process the requests, but pull the information appropriately. Having the mapping classes will definitely work for multiple formats, but if the data contents are wildly different, the benefit does start to break down as you handle one-offs. \$\endgroup\$
    – J Torres
    Jul 17, 2012 at 13:39
  • \$\begingroup\$ J Torres - If you have the time, would you mind showing an example with the builder pattern with dependency injection? Thanks for your patience. \$\endgroup\$
    – Xaisoft
    Jul 17, 2012 at 13:42
  • \$\begingroup\$ I still think this basic idea is the best conceptually, even if the data required in each XML is almost totally different; have one main "domain" class with the information, that can then be digested by one or more serializers chosen by strategy pattern. \$\endgroup\$
    – KeithS
    Jul 17, 2012 at 15:25
  • \$\begingroup\$ -1. Factory is the right idea, but the implementation here makes no sense. All those methods should be inside the factory class. The factory figures out what kind of serializer to build, builds one and holds onto it. The client should make 3 calls, passing stuff to the factory as needed. 1) initial factory creation, 2)convert XML to a rental car list, 3)convert a rental car list to XML. \$\endgroup\$
    – radarbob
    Jul 17, 2012 at 19:05
0
\$\begingroup\$

This is a factory pattern because the client uses a class (the factory) to build the Rental car information list.

It strikes me that this is almost the builder pattern. The Builder is simply an object that encapsulates the building of a more complex object. IF, along with building a particular ISerializerFactory we had to build a custom version of the RentalCar to go along with it - well then RentalCarBuilder's class diagram would look like a builder pattern I believe.

So it occurs to me that perhaps a Builder (pattern) is simply an encapsulation for a more complex Factory (pattern).

 
// client code
XDocument rentals = ReadTheXML();
RentalCarBuilder rentalData = new RentalCarBuilder(rentals);
List myRentals = rentalData.RentalList();
RentalDealerForm RentalCompany = rentalData.theDealerForm;

// the details

public class RentalCarBuilder() {
    protected ISerializerFactory mySerializer;
    protected XDocument rentalXml;
    protected RentalDealerForm    theDealerForm;

    public void Create (XDocument rentalCarXml) {
        rentalXml = rentalCarXml;
        mySerializer = BuildSerializer(rentalCarXml);
    }

    public List RentalList () {
        return mySerializer.CreateRentalList(rentalXml);
    }

    protected void BuildSerializer (XDocument rentalCarXml) {
        // magic to figure out what form of the xml we're dealing with
        // for fun, i'm going to assume we figure it out and capture that
        // with an enumeration.
        theDealerForm = WhatDealerIsThis(rentalXml);
        mySerializer = new RentalCarSerializerFactory(theDealerForm);
    }

    protected RentalDealerForm WhatDealerIsThis(XDocument rentalXml) {
        RentalDealerForm  who;
        // more magic

        return who;
    }
}

public class RentalCarSerializerFactory {
    // methods to build the appropriate class below
}

public class BudgetSerializer : ISerializerFactory () {}
public class RentAWreckSerializer : ISerializerFactory() {}
public class EnterpriseSerializer : ISerializerFactory() {}


public enum RentalDealerForm {
    Budget
    ,Enterprise
    ,RentAWreck
}

public class RentalCar {
    public Customer renter {get; set;}
    public DateTime Pickup {get; set;}
    public DateTime Dropoff {get; set;}
    public double Deposit {get; set;}

}
\$\endgroup\$
2
  • \$\begingroup\$ You make some great points, but I am confused on certain things because I am not too good with design patterns. I will add a comment with some questions, but I want to give you an idea of one scenario I run into: Each agency can update their car inventory by passing xml to a specific web-service, so for example, agency one will pass inventoryupdate.xml to service a and agency two will pass inventoryupdate.xml to service b. Each service (a and b) have their own set of classes, but I don't like this because a lot of the code is the same and I would like to share and reduce code. \$\endgroup\$
    – Xaisoft
    Jul 18, 2012 at 13:50
  • \$\begingroup\$ Is ReadTheXml just the same as XDocument.Load? I don't see a constructor for RentalCarBuilder? What is it supposed to do with the rentals argument? What is RentalList() supposed to do? and why return a list? What if I am just dealing with one rental? I am confused on what RentalDealerForm is supposed to be? What should the defenition of ISerializerFactory be? \$\endgroup\$
    – Xaisoft
    Jul 18, 2012 at 13:53

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.