Design patterns and practices in .NET: the Adapter Pattern

The adapter pattern is definitely one of the most utilised designed patterns in software development. It can be used in the following situation:

Say you have a class – Class A – with a dependency on some interface type. On the other hand you have another class – Class B – that would be ideal to inject into Class A as the dependency, but Class B does not implement the necessary interface.

Another situation is when you want to factor out some tightly coupled dependency. A common scenario would be a direct usage of some .NET class, say HttpRuntime in a method that you want to test. You must have a valid HttpRuntime while running the test otherwise the test may fail and that is of course not acceptable. The solution is to let the method be dependent on some abstraction that is injected to it – the question is how to extract HttpRuntime and make it implement some interface instead? After all, it’s unlikely that you’ll have write access to the HttpRuntime class, right?

The solution is to write an adapter that sits between Class A and Class B that wraps Class B’s functionality. An example from the real world: if you travel from Britain to Sweden and try to plug in your PC in your hotel room you’ll fail as the electric sockets in Sweden are different from those in the UK. Class A is your PC’s power plug and Class B is the socket in the wall. The two objects clearly don’t fit but there’s a solution: you can insert a specially made adapter into the socket which makes the “conversion” between the plug and the socket enabling you to pair them up. In summary: the adapter pattern allows classes to work together that couldn’t otherwise due to incompatible interfaces. The adapter will take the form of an interface which has the additional benefit of extensibility: you can write many implementations of this adapter interface making sure your method is not tightly coupled to one single concrete implementation.

Demo

Open Visual Studio and create a new blank solution. Add a new class library called Domain and delete Class1.cs. Add a new class to this project called Customer. We’ll leave it void of any properties, that is not the point here. We want to expose the repository operations by an interface, so insert an interface called ICustomerRepository to the Domain layer:

This bit of code should be straightforward: we want to return a list of customers using the abstract dependency ICustomerRepository. We check if the list is available in the HttpContext cache. If that’s the case then convert the cached value and return the customers. Otherwise fetch the list from the repository and put the value to the cache.

So what’s wrong with the GetAllCustomers method?

Testability

The method is difficult to test because of the dependency on the HttpContext class. If you want to get any reliable result from the test that tests the behaviour of this method you’ll need to somehow provide a valid HttpContext object. Otherwise if the test fails, then why did it fail? Was it a genuine failure, meaning that the customer list was not retrieved? Or was it because there was no HttpContext available? It’s the wrong approach making the test outcome dependent on such a volatile object.

Flexibility

With this implementation we’re stuck with the HttpContext as our caching solution. What if we want to change over to a different one, such as Memcached or System.Runtime? In that case we’d need to go in and manually replace the HttpContext solution to a new one. Even worse, let’s say all your service classes use HttpContext for caching and you want to make the transition to another caching solution for all of them. You probably see how tedious, time consuming and error-prone this could be.

On a different note: the method also violates the Single Responsibility Principle as it performs caching in its body. Strictly speaking it should not be doing this as it then introduces a hidden side effect. The solution to that problem is provided by the Decorator pattern, which we’ll look at in the next blog post.

Solution

It’s clear that we have to factor out the HttpContext.Current.Cache object and let the consumer of CustomerService inject it instead – a simple design principle known as Dependency Injection. As usual, the most optimal option is to write an abstraction that encapsulates the functions of a cache solution. Insert the following interface to the Service layer:

We’ve got rid of the HttpContext object, so the next task is to inject it somehow using the ICacheStorage interface. This is the essence of the Adapter pattern: write an adapter class that will resolve the incompatibility of our home-made ICacheStorage interface and HttpContext.Current.Cache. The solution is really simple. Add a new class to the Service layer called HttpContextCacheStorage:

This is the adapter class that encapsulates the HttpContext caching object. You can now inject this concrete class into CustomerService. In the future if you want to make use of a different caching solution then all you need to do is to write another adapter for that: MemCached, Velocity, System.Runtime.Cache, you name it.

If you have multiple caching concrete caching storage mechanisms that implement ICacheStorage, then yes, you can apply the Strategy pattern to choose the correct one based on some external parameters. However, hiding the concrete implementations behind abstractions is still best done with the Adapter pattern I think.

I think it’s actually Strategy. Adapter makes possible that objects with incompatible interfaces can work together. In this case that is not the problem.

The problem here is that you need to decouple your CustomerService from the Caching mechanism for testability purposes. That is served with a strategy pattern.

However I can see that in the future, when you decide to substitute your caching layer for something more advanced like Memcached, it’s possible that you could end with some Caching object that doesn’t conform to your interface. In that case, you’d be actually writing an adapter so your CustomerService can work with it.

While this is a good example to explain DI, the need for the adapter pattern doesn’t come until the end. I think the classic example would be when you have a common interface to access say a third party API and you create an adapter for each third party API.

While the post is simple and elegant, adapter pattern doesn’t come very clearly unless one focuses on ‘testability’ nature. For me the classic adapter example in .Net is interop assemblies: you need to deal with COM components from managed (or vice versa) and you hit the runtime constraints which are solved by interop tools.

I like your explanation though I do have one suggestion.
When I started learning .NET, the term that kept popping up was “Wrapper”. It might help to explain that the 2 are actually synonymous because I only got to know it as an “Adapter” way later in personal research.

Wikipedia calls it “Adapter or Wrapper or Translator”.

Seeing how naming conventions and vocabulary are really important and people across the globe might use different names for this pattern (unofficially, they might not even know it’s a pattern like it was for me)

I know its an old post, but .. what happens when you want to test the Adapter class “HttpContextCacheStorage”. Don’t you still have the HttpContext object to deal with ? Its like the problem is being moved from one class into another.