1

I have a scenario I am coding, where I feel the Adaptor Pattern would be useful. I have a service that has multiple possible providers I want to switch when I like, so as long as each "Adapter" follows the same rules (interface) the underlying code is hidden from the caller.

With this in mind, I've been looking at a number of examples. This code snippet is taken from this stack overflow example:

Interface ITarget
{
  public void GetData();
}

//Decision to use MSDAO
class AdaptorMS : ITarget
{
  public void GetData()
  {
    MSDAO objmsdao = new MSDAO();
    objmsdao.GetDataMethod();
  }
}

// calling code
class Client
{
  static void Main(string[] args)
  {
    ITarget objAdaptor = new AdaptorMS();
    object dummyObject = objAdaptor.GetData();
  }
}

Then we decide to create a new adaptor that we will change to:

//After a month, the decision to use OracaleDAO was taken, so create a new adapter
class AdaptorOracle: ITarget
{
  public void GetData()
  {
    OracleDAO objrracledao = new OracleDAO();
    objoracledao.GetSomeData();
  }
}

// Calling code
class Client
{
  static void Main(string[] args)
  {
    ITarget objAdaptor = new AdaptorOracle();
    object dummyObject = objAdaptor.GetData();
  }
}

I've also seen this example:

public class AdaptorA : ITarget
{
     private TargetA A { get; set; }

     public AdaptorA( TargetA a )
     {
           this.A = a;
     }

     public void GetData() { 
          return this.A.SomeGetDataCall(); 
     }
}

public class AdaptorB : ITarget
{
     private TargetB B { get; set; }

     public AdaptorB( TargetB a )
     {
           this.B = a;
     }

     public void GetData() { 
          this.B.MakeDataCall(); 
     }
}

We have two new adaptors but what I don't understand about the above example, is the fact the Adaptor class takes a parameter for the underlying system it will call (TargetA or TargetB). What's the difference in the two examples? I get the first example, hiding all implementation from the calling code (instance of OracleDAO is inside the adaptor), but not the second. Is there a fundamental difference or have I misunderstood the pattern?

Thanks in advance for any advice!

Rob
  • 6,819
  • 17
  • 71
  • 131
  • 1
    In the question that you've linked there is a great answer (the accepted one). Did you read it carefully? is there something specific that that answer doesn't address or is not clear to you? – Ofir Winegarten Aug 26 '18 at 11:10
  • Yea I seen that one, and understand the concept that the pattern will allow a common interface where one may not exist BUT as with the answer's example (which I copied above), I just don't get why the instance of TargetA is passed to AdaptorA - will callers have an instance of TargetA already that they want to pass to an adaptor, that then can be passed around with a common interface? I was kind of thinking the pattern was to remove the need of the caller to know anything about TargetA but I may have presumed that incorrectly. – Rob Aug 26 '18 at 11:59
  • 1
    Well, actually this is a classic case to use adapter. You have an object, but it doesn't fit your desired interface, so you build an adapter for it, pass it the incompatible object and use the adapter instead. Who said that the adapter has to create it? maybe you use that object already in the system, and you just need an adapter at a particular point in the system. – Ofir Winegarten Aug 26 '18 at 12:04
  • Ah ok cool - I get it now! The different examples hadn't really explained that and it threw me. Thanks for the clarification. In my case I will probably hide the instance of the class I want to call hidden within the Adaptor itself but see why the other scenario may be needed also. If I do this - it still is the Adaptor pattern, right? – Rob Aug 26 '18 at 12:09
  • 2
    Good question, I guess it is, why not. – Ofir Winegarten Aug 26 '18 at 12:25
  • 1
    see below also in case this point was missed.... – bcperth Aug 27 '18 at 00:06
  • Sadface at the down votes! :( this question wasnt broad - it specifically asks the difference between two examples! – Rob Aug 27 '18 at 18:51

1 Answers1

1

There is a key difference between the above two implementations of Adaptor.

To recap, Adaptor is no more than a wrapper for different classes whose purpose is to provide a common interface. It can be implemented either using double inheritance (class adaptor) or by composing and instance of the adaptee within the adaptor (object adaptor).

The examples above are both "object adaptors"(as per GoF definition).

Example 2 however is actually a combination of Strategy and Adaptor, providing an extra layer of decoupling between the Adaptor classes and the Adaptees. This is more flexible and more compliant with the "D" in SOLID.

With this in mind the reader is now invited to dream up use cases where each version is more appropriate than the other. But when presented in isolation as above, the fact that they are different and have different uses is easily lost.

Not sure the commentary above covered this point?

bcperth
  • 2,191
  • 1
  • 10
  • 16
  • 1
    @pere57 In example 1, the target is instantiated in the subclass. AdaptorMS subclass is bound to a specific MSDAU class. In example 2, we are passing in (injecting) an MSDAU object but could be any class that implements MSDAU's interface. This injection is what Strategy is about. Example 2 is more flexible, because of the decoupling, allowing (for example) later version objects of the MSDAU class to be injected, without changing the AdaptorMS class. – bcperth Aug 27 '18 at 09:34
  • Guys this is a great further explanation! Thank you very much! It looks like I'm implementing the Adaptor pattern (not Strategy Adaptor) but this really helps me understand the difference between the two types, as it was this difference that confused me at first (and prompted my question!) – Rob Aug 27 '18 at 18:48
  • @peres. In example 2, we know TargetA and TargetB are instantiated objects, injected into the constructors of AdaptorA and B respectively. How else can we invoke `this.A.SomeGetDataCall();` ? Is this how you see it? Maybe we are saying the same thing? – bcperth Aug 27 '18 at 22:58
  • @peres. Yes I agree. TargetA could be a regular class and it surely is in the example. But example 2 allows for the flexibility that TargetA later becomes a sub-class if for example Oracle published several versions of its DAO, each with the same interface. Then choosing the version is Strategy by "selecting of an algorithm at runtime via a concrete implementation"?. Its all a bit academic I agree :-) – bcperth Aug 28 '18 at 02:14