Update: I added some diagrams to help understanding
I had a discussion with a colleague about two different approaches in mapping data objects. I'd like to get your opinion on pros and cons between the two approaches.
Some background information. We have two external services. One is reached over SOAP, the other over REST. They return objects of similar nature (postal delivery points). As they are different external services, the data objects are different. For example (oversimplifying the actual data objects):
public partial class ParcelShopA
{
public string City { get; set; }
public string Address1 { get; set; }
}
and service 2 might be:
public partial class ParcelShopB
{
public AddressB Address { get; set; }
}
public partial class AddressB
{
public string Street { get; set; }
public string HouseNumber { get; set; }
public string City { get; set; }
}
Now, the objective is to combine the responses of the two services into a single unified format and expose that. So we have our own class:
public class UnifiedAddress
{
public string Address { get; set; }
public string City { get; set; }
}
Here's a diagram showing the initial problem, before applying any solution:
Approach 1: My idea was to create separate mapper per case. In my mind, it's simple functional programming case, where we want to go from object A to object B.
public class ConverterA
{
public UnifiedAddress ConvertToUnified(ParcelShopA p)
{
// TODO implement
}
}
and the same for B:
public class ConverterB
{
public UnifiedAddress ConvertToUnified(ParcelShopB p)
{
// TODO implement
}
}
Now, keep in mind, each service will be implemented within a separate code project (probably a separate microservice as well), so all logic will be contained there.
Here's how that solution would look like:
Approach 2: The alternative approach was something like this:
- Define an interface like
IParcelShop
that defines the requirements for all parcel shops - Define a class that converts from
IParcelShop
to the unified address - Since we're in C# and we have partial classes, implement
IParcelShop
in each data object.
So we'll have something like:
public interface IParcelShop
{
string GetAddress();
string GetCity();
}
and the mapper converts from IParcelShop
:
public class Mapper
{
public UnifiedAddress Convert(IParcelShop parcelShop)
{
return new UnifiedAddress
{
City = parcelShop.GetCity(),
Address = parcelShop.GetAddress()
}
}
}
Now, since we have partial classes, we can add this functionality to the data objects of the services, e.g. for the first parcel shop it would be:
partial class ParcelShopA : IParcelShop
{
public string GetAddress() => Address1;
public string GetCity() => City;
}
and for the second maybe:
partial class ParcelShopB : IParcelShop
{
public string GetAddress() => Address.Street + " " + Address.HouseNumber;
public string GetCity() => Address.City;
}
Here's a diagram showing the second solution:
In my mind the first approach is much cleaner because it does not touch the data objects, does not rely on partial classes and contains the mapping logic in a single place.
What arguments would you present to someone to convince him/her in favor of one or the other solution?