Factory, different API

Hi!

We have a solution where a factory returns the correct dataprovider which in turn returns the correct dataobjects. The problem is that we f.ex. have one provider that uses the external system X and another that uses the external system Y which in turn needs different arguments to return the same data.

XProvider.GetWorkOrder(string arg1, string arg2, long arg3) : WorkOrder
YProvider.GetWorkOrder(string arg1) : WorkOrder

Is there anyone that has a solution on this problm




Answer this question

Factory, different API

  • Wahl04

    It means you'll need to unify the API as it is exposed to your application. One way to do this is to go with the maximum number of possible inputs, instead of the minimum.
    Here's an example:

    A few years ago I worked on an application that did a credit risk assesment. That assesment was computed after getting information out of 5 or 6 different applications (some part of the same company, some external services). Each one of those required a different set of inputs, and gave a different set of outputs. For example, one just asked for your national ID number, while others needed to know even how many cars you owned. Still we needed to provide a uniform way to access them.

    What we did was create a single interface through which all services were accessed. The input to that interface was actually the *entire* set of fields of data we had on the person, regardless of whether the underlying external system/provider used them. So, each service gateway implementation simply discarded fields it didn't need and used the ones it did, and that was that. Worked very nicely, btw.

    With this, you don't need to check which provider the application is asking for, since the interface to access them is the same regardless of the data they ask for. The logic however moves to the provider implementation itself, which now has to be able to sort what data it needs and what not.

    Look, at the end of the day, if each provider has different requirements, *somewhere* you're gonna have to put code to deal with it. It's not going to go away. However, with careful design you can put it where it takes the least work, is less risky and provides you with the greatest flexibility. Doing it as I mentioned, is one possible solution to it which has worked well for me in the past, but ceretainly YMMV.


  • leovernazza

    But doesn't that mean that we have to check which Provider the caller app is asking for and f.ex. add some extra arguments

  • satya999

    Another option is to create parameter objects that implement a common interface / base class that exposes the common properties. Then within your providers you cast appropriately. So for example.

    public abstract class WorkOrderParameters {
      public string arg1 //only for illustration should be a property
    }
     
    public class XWorkOrderParameters : WorkOrderParameters {
      public string arg2; //illustration only
      public string arg3; //illustration only
    }
     
    public class YWorkOrderParameters : WorkOrderParameters {
    //no props needed as we get the prop from the base
    }

     Now you can also have a provider interface that has the GetWorkOrder method with one signature.

    public interface IProvider {
       WorkOrder GetWorkOrder(WorkOrderParams params);
    }
     
    public class XProvider : IProvider {
      public WorkOrder GetWorkOrder(WorkOrderParameters params) {
        XWorkOrderParams OrderParams = (XWorkOrderParams) params;
        ... //Code that retrieves and returns the workorder
      }
    }
     
    public class YProvider : IProvider {
      public WorkOrder GetWorkOrder(WorkOrderParams params) {
        YWorkOrderParams OrderParams = (YWorkOrderParams) params;
        ... //Code that retrieves and returns the workorder
      }

    }

    With this method you can enforce type safety on the methods so that only valid param objects are passed, share common properties (if they exist), yet still differentiate for the different providers, without having to provide all the properties for all providers just to keep the signature consistent. Your providers now all share a common interface so you can invoke your providers all with a common set of code. i.e. see below

    IProvider Provider = GetProvider() //some method that returns the provider, could be XProvider, or YProvider.
    WorkOrderParams Params = GetParams() //some method that returns the params,
                                                             //could be XWorkOrderParams or Y.
    WorkOrder Order = Provider.GetWorkOrder(Params); //Get the work order.
     

    Serveral other advantages are:

    1. You can change your parameter objects over time, without breaking your main interface or haivng to change your GetWorkOrder signature.

    2. You can add new providers with ease. GetProvider could return an unlimited set of providers and as long as they implement the correct interface the code will work.

    3. Your providers only see the information they need. You don't have to worry about accessing the wrong parameter because there is no wrong parameter. Each provider only sees the parameters it should based on each having their own specific parameter object implementations.

    4. You can have generic code upstream that handles common functionality using the interfaces and base classes.

    Now you still need your app to create the correct Provider instance and Parameter instance to pass to the common method. But you can handle this upstream. This is what I was hinting at with my GetProvider / GetParams methods above.

    If it doesn't make sense, let me know.



  • sea2006

    Sounds like your problem is that both providers don't have a uniform (i.e. the same) interface. If so, you migth want to just apply the pattern on a slightly above level of abstraction of your system, in a place where you *can* define a uniform interface for both systems and abstract (encapsulate) the difference away. Something like the Service Gateway pattern might be helpful here.


  • Factory, different API