2

I have little doubt about adapter class. I know what's the goal of adapter class. And when should be used. My doubt is about class construction. I've checked some tutorials and all of them say that I should pass "Adaptee" class as a dependency to my "Adapter". e.g.

Class SampleAdapter implements MyInterface
{
    private AdapteeClass mInstance;
    public SampleAdapter(AdapteeClass instance)
    {
         mInstance=instance;
    }
}

This example is copied from wikipedia. As you can see AdapteeClass is passed to my object as dependency. The question is why? If I'm changing interface of an object It's obvious I'm going to use "new" interface and I won't need "old" one. Why I need to create instance of "old" class outside my adapter. Someone may say that I should use dependency injection so I can pass whatever I want, but this is adapter - I need to change interface of concrete class. Personally I think code bellow is better.

Class SampleAdapter implements MyInterface
{
    private AdapteeClass mInstance;
    public SampleAdapter()
    {
         mInstance= new AdapteeClass();
    }
}

What is your opinion?

Ivan
  • 2,262
  • 1
  • 18
  • 16
  • I think you are looking for decorator ... – dotnetstep Jan 12 '12 at 16:17
  • 1
    @dotnetstep No, the Adapter pattern he is referring to is different from decorator. Decorator will keep the interface the same but will extend the behaviour. Adapter reworks the interface of an existing class to match an expected interface Check http://stackoverflow.com/questions/350404/how-do-the-proxy-decorator-adaptor-and-bridge-patterns-differ for more info – Wouter de Kort Jan 12 '12 at 16:22

4 Answers4

8

I would say that you should always avoid the new operator in a class when it comes to complex objects (except when the class is a Builder or Factory) to reduce coupling and make your code better testable. Off course objects like a List or Dictionary or value objects can be constructed inside a class method (which is probably the purpose of the class method!)

Lets say for example that your AdapteeClass is a Remote Proxy. If you want to use Unit Testing, your unit tests will have to use the real proxy class because there is no way to replace it in your unit tests.

If you use the first approach, you can easily inject a mock or fake into the constructor when running your unit test so you can test all code paths.

Google has a guide on writing testable code which describes this in more detail but some important points are:

Warning Signs for not testable code

  • new keyword in a constructor or at field declaration
  • Static method calls in a constructor or at field declaration
  • Anything more than field assignment in constructors
  • Object not fully initialized after the constructor finishes (watch out for initialize methods)
  • Control flow (conditional or looping logic) in a constructor
  • Code does complex object graph construction inside a constructor rather than using a factory or builder
  • Adding or using an initialization block
Wouter de Kort
  • 39,090
  • 12
  • 84
  • 103
  • Sorry, I don't buy it - *you should **always** avoid the new operator in a class (except when the class is a Builder or Factory)* - at all, please read my answer about "is new operator evil?!" - it's here http://stackoverflow.com/questions/8690720/factory-design-pattern-and-keyword-new/8693412#8693412 – dantuch Jan 12 '12 at 16:26
  • 1
    I'm agree about avoiding new operator in a class and couplings at all. But the goal of adapter is to change interface of given class. In other words both classes must be coupled. Anyway you're right about mocks. – Ivan Jan 12 '12 at 16:53
  • 1
    Agree. The adapter's purpose is to adapt one interface to another; construction is another responsibility. The moment you new up the instance inside the adapter, you lose the ability to program to an interface and you also explicitly set the ownership/lifetime of the adaptee instance. These are both things that may need to be controlled elsewhere (e.g. in a DI container). – Mark Simpson Jan 12 '12 at 18:00
  • 1
    @dantuch Your right in stating that the new operator is not evil when we're talking about 'simple' objects like a Lists or a value object. I'll modify my answer to be a little less strict :) – Wouter de Kort Jan 12 '12 at 20:44
1

AdapteeClass can have one or more non-trivial constructors. In this case you'll need to duplicate all of them in your SampleAdapter constructor to have the same flexibility. Passing already constructed object is simpler.

Andriy Tylychko
  • 15,967
  • 6
  • 64
  • 112
0

Let's assume you have an external hard drive with a regular USB port and you are trying to hook it up with a Mac which only has type-c ports. Yes, you can buy a new drive which has a type-c port but what about the data in it?

It's the same for the adapter pattern. There're times you initialize AdapteeClass with tons of flavors. When you do the conversion, you want to keep all the context.

0

I think creating the Adaptee inside the Adapter is limiting. What if some day you want to adapt a pre-existing instance?

To be honest though, I'd do both if at all possible.

Class SampleAdapter implements MyInterface
{

    private AdapteeClass mInstance;

    public SampleAdapter()
       : base (new AdapteeClass())
    {
    }

    public SampleAdapter(AdapteeClass instance)
    {
         mInstance=instance;
    }
}
tcarvin
  • 10,715
  • 3
  • 31
  • 52