C# Dependency Injection with Adapter Pattern

adaptercdependency-injectioninversion-of-control

In the following code sample, I have a client that works through a controller. In my specific case the controller establishes a session to an address on a GPIB bus. An instance of this is then injected into the client class, which in my case is a device. The client class knows what to say to the device and uses the controller to pass those messages to the device.

Where I get into trouble is there are various ways to talk to the device. I have created so far ITextReader, ITextWriter, IBinaryReader, IBinaryWriter, and there may be more in the future. The implementations of these interfaces is done in the adapter assembly because that is the only assembly that knows how to talk to the adaptee. The controller and client only have references on the controller.api assembly.

How then does the client ask for an instance of the adapter's TextReader, for which it has no reference to? I figure there is some combination of using a factory pattern and an IoC container (using Unity), but I can't come up with a design where the client can get an instance of any of those reader\writer implementations.

Adapter Assembly:

public class Adapter : IAdapter
{
    public class Adapter(IAdaptee adaptee){..}
}

public class TextReader : TextReaderBase, ITextReader
{
    TextReader(IController controller)
    : base(controller)
    {..}

}

Controller.Api Assembly:

public interface IAdapter{...}
public interface ITextReader{...}
public interface ITextWriter{...}

Controller Assembly:

public class Controller : IController 
{
    Controller (IAdapter adapter){...}
}

public abstract class TextReaderBase : ITextReader
{
    TextReaderBase(IController controller){..}
}

Client Assembly:

public class Client : IClient
{
    Client (IController controller){...}
}

Edited 6/6/2015:

I should make it clearer what I am trying to do. The 3rd party library (adaptee) has low level functions for reading, writing, opening connections, etc. The high level classes for establishing connections, reading, and writing is what I was referring to as the controller. The adapter adapts the 3rd party library to this controller. I made additional interfaces to represent the low level reader\writer like IAdapterReader and IAdapterWriter.

The clients work exclusively through the controller, knowing nothing of the low level adapter stuff. In my current design, I was planning to have a service that reads a config file to find which adapter to instantiate and the address of the device. It creates an instance of this adapter, injects this into the controller class and then injects the controller object into the client. I am calling the controller class here a "session" to represent a connection to a specific address on the bus. The idea is that the client knows what to say to the device (commands and such) and the controller knows how to say it (has access to the physical layer).

For the client to actually talk to the device, I was thinking they would ask for a reader and a writer instance, but clearly this is not then dependency injection. For the client to ask for a reader\writer it would have to know about the adapter as my high level reader\writers wrap the low level ones implemented by the adapter.

I guess the question then is how does the client get a reader\writer? I can think of a crude way by injecting into the client ISession, ITextReader, ITextWriter, IBinaryReader, IBinaryWriter and any other interfaces it may need? The other way is to inject only ISession and make ISession have a T Resolve<T>(Type type) method. The implementation of Resolve could be through an IoC container. I could change the design around so that when the adapter object is being created it also registers all of its implementations with interfaces with an IoC container passed in from the service layer.

Best Answer

Right now what I see is the following chain of dependencies:

client->controller->adapter->reader->controller

That does create a circular dependency.

You use Dependency Injection to achieve Dependency Inversion. That is, that higher level code does not dependent on the implementation of lower level code.

Looking at the chain, we can attest that there is a piece of code, either the controller or the text reader, that is both high and low level.

If the client does need to use directly the text reader then it cannot be that the adapter uses it as well, as you would need to inject it further up. Rather you will be injecting the adapter into the text reader. And then injecting the text reader into the client.

But if we do that, and we keep the injection of the controller both on the client and the text reader, are we not, then, exposing incorrectly functionality? Because you are saying both that the text reader is of the same level than the controller, and that the controller is at a lower level than the text reader (as it is injected)

Finally, why does the client need to access the text reader used by the adapter? If there is really something that is needed you can provide a pass through method that doesn't expose the fact that you have the text reader somewhere down there.

Check which functionality is going to be lower level (which one actually does the writing/reading) and which one does the high level stuff. Order them higher to level and inject lower into higher.

Without looking at the code,I am imagining that the actual order would be

client->controller->adapter->text read/write 

And that in fact the text reader/writer doesn't need to know about the controller because it is the one reading/writing directly from/to the device. Any information that the controller has that the text reader/writer needs will be passed through parameters.

Related Topic