views:

120

answers:

2

I've used a fair amount of dependency injection, but I'd like to get input on how to handle information from the user at runtime.

I have a class that connects to a com port. I allow the user to select the com port number. Right now, I have that com port parameter as a constructor argument. The reasoning being that the class cannot function without that information, and it's implementation specific (a mock version of this class wouldn't need a com port).

The alternative is to have a "Start" method that takes in the com port, or have a property that sets the com port. This makes it very compatible with an IoC container, but it doesn't necessarily make sense from the perspective of the class.

It seems like the logical route conflicts with the dependency injection design, but it's because my UI is getting information for a specific type of class.

Other alternatives would include using an IoC container that lets me pass in additional constructor parameters, or just constructing the classes I need at the top level without using dependency injection.

Is there a generally accepted standard pattern for this type of problem?

A: 

Most IoC containers have some form of Constructor Injection that would allow your IoC container to pass a mocked COM port into your class for unit testing. That seems like the most clean solution.

I would avoid adding a "Start" method, etc. Its much better practice to (when possible) always have your classes in a valid state, and switching to a parameterless constructor with a start method leaves your class invalid between those calls. Doing this to enable testing is just making your class more difficult in order to test (which should make it nicer).

Reed Copsey
Sorry, I should have been more clear. The com port is simply a number. Testing is not an issue, as I can create a mock version of the class. I don't know the com port ahead of time, I get it from the user. Since that's the case, it seems kind of silly to have the UI use an interface, since it needs an implementation that needs a com port.
Jason Young
+1  A: 

There are two routes you can take, depending on your needs.

1. Wire the UI directly to your concrete classes

This is the simplest option, but many times perfectly acceptable. While you may have a Domain Model with lots of interfaces and use of DI, the UI constitutes the Composition Root of the object graphs, and you could simply wire up your concrete class here, including your requrired port number parameter.

The upside is that this approach is simple and easy to understand and implement.

The downside is that you get less flexibility. You will not be able to arbitrarily replace one implementation with another (but then again, you may not need that flexibility).

Even with the UI locked to a concrete implementation, this doesn't mean that the Domain Model itself wouldn't be reusable in other applications.

2. Add an Abstract Factory

The other option is to add another layer of indirection. Instead of having your UI create the class directly, it could use an Abstract Factory to create the instance.

The factory's Create method could take the port number as an input, so this abstraction belongs best in a UI sub-layer.

public abstract class MyFactory
{
    public abstract IMyInterface Create(int portNumber);
}

You could then have your DI container wire up an implementation of this factory that uses the port number and passes it as a constructor argument to your real implementation. Other factory implementations may simply ignore the parameter.

The advantage of this approach is that you don't pollute your API (or your concrete implementations), and you still have the flexibility that programming to interfaces give you.

The disadvantage is that it adds yet another layer of indirection.

Mark Seemann