2

I know what you're thinking... "This is a duplicate of

This is however not the case.

Scenario

I have two production systems that have the same type of data and they each have their own API. Unfortunately some of the API calls for these systems are different and some are the same. I want to create a generic interface/translation layer that would convert generic calls into the respective calls of the system being queried

During startup, the integration would check which version of the production system it needs to connect to and store that value in a variable. When I call "GetVehicle" I want to automatically translate this request into either "GetTruck" or "GetCar" based on the value of the previously defined variable.

Below is a short pseudo-code-ish example of what I'm trying to accomplish.

NOTE: You can skip to the bottom of the page if you want to read the question first.

There will be an enum

public enum TypesOfVehicles
{
    Commercial,
    Residential
}

The main program would instantiate the object and set the variable, then perform some action on the instantiated object.

internal static class Program
{
    static void Main(string[] args)
    {
        var doStuffWithVehicles = new DoStuffWithVehicles();
    
        doStuffWithVehicles.TypeOfVehicle = TypesOfVehicles.Commercial;
        
        var myTruck = doStuffWithVehicles.GetVehicle(1);
        
        doStuffWithVehicles.TypeOfVehicle = TypesOfVehicles.Residential;
        
        var myCar = doStuffWithVehicles.GetVehicle(1);
    }
}

DoStuffWithVehicles would be the "middleware/translation" layer for the two production systems. There are substantially more than two methods that would have to be mapped?

public class DoStuffWithVehicles
{
    public TypesOfVehicles TypeOfVehicle { get; set; }
    
    public T GetVehicle(int id)
    {
        switch (TypeOfVehicle)
        {
            case TypesOfVehicles.Commercial:
                return HeavyVehicle.GetTruck(id);
                break;
            case TypesOfVehicles.Residential:
                return LightVehicle.GetCar(id);
                break;
        }
    }
    
    public int GetWheels(int id)
    {
        switch (TypeOfVehicle)
        {
            case TypesOfVehicles.Commercial:
                return HeavyVehicle.GetWheels(id);
                break;
            case TypesOfVehicles.Residential:
                return LightVehicle.GetWheels(id);
                break;
        }
    }
}

And the production system classes would look something like this

public class HeavyVehicle
{
    public T GetTruck(int vehicleId)
    {
        return commercialContext.Query<HeavyVehicleObj>().Where(x => x.id == vehicleId);
    }
    
    public int GetWheels(int vehicleId)
    {
        return commercialContext.Query<HeavyVehicleObj>().Where(x => x.id == vehicleId).Select(x => x.nrOfWheels).FirstOrDefault();
    }
}

and

public class LightVehicle
{
    public T GetCar(int id)
    {
        return residentialContext.Query<LightVehicleObj>().Where(x => x.id == id);
    }
    
    public T GetWheels(int id)
    {
        return residentialContext.Query<LightVehicleObj>().Where(x => x.id == vehicleId).Select(x => x.nrOfWheels).FirstOrDefault();
    }
}

Question Is there a way to build this type of interface/translation layer without having to create a switch for every single method that exists in both of the production system APIs?

Due to the performance impact of reflection (the system performs 100s of transactions per second and all of them include a SQL component), it is not an option.

  • 1
    Take a look at the [Bridge design pattern](https://www.dofactory.com/net/bridge-design-pattern), but instead of the consumer setting the implementor, have the class set it when the `TypeOfVehicle` property changes (use a `switch` in the `set` accessor and `new` up the right type). The methods in `DoStuffWithVehicles` just call the underlying implementor's methods by the same name. – madreflection Nov 09 '21 at 21:28

0 Answers0