Login | Register   
LinkedIn
Google+
Twitter
RSS Feed
Download our iPhone app
TODAY'S HEADLINES  |   ARTICLE ARCHIVE  |   FORUMS  |   TIP BANK
Browse DevX
Sign up for e-mail newsletters from DevX


advertisement
 

Layered Architecture, Dependency Injection, and Dependency Inversion : Page 3

Building loosely coupled application architectures requires more than just separating your application into different layers.


advertisement
Dependency Injection and Inversion in the Service Layer
Listing 4 shows that all the code stripped from the presenter seems to have gone the way of the Dodo bird. I can address that by creating an implementation of the IEmployeeTask interface in the service layer. Listing 5 shows my first take at an implementation of the service. This can't be right. Did I do all that work to clean up my UI and presenter only to come down to the service layer and duplicate the mistakes that started me down this path in the first place? Armed with the new knowledge I have about dependency inversion and dependency injection I can now clean up the dependency on implementations rather than abstractions. I'll start by introducing a new interface into the mix:

public interface IConnectionFactory { IDbConnection Create(); }

With the IConnectionFactory interface created I can use dependency injection to ensure that the service layer class is constructed with an IConnectionFactory:

public EmployeeTaskLowCohesion NoDependencyInversion( ConnectionFactory connectionFactory) { this.connectionFactory = connectionFactory; }

That small change allows me to change the code in the GetEmployees method to that shown below:



public DataTable GetEmployees() { using (IDbConnection connection = connectionFactory.Create()) { using (IDbCommand command = connection.CreateCommand()) { command.CommandText = "SELECT * FROM Employees"; command.CommandType = CommandType.Text; connection.Open(); using (IDataReader reader = command.ExecuteReader( CommandBehavior.CloseConnection)) { DataTable results = new DataTable(); results.Load(reader); return results; } } } }

Notice that the GetEmployees method is no longer coded to an explicit SqlClient implementation; it now uses abstractions defined in the System.Data namespace, which (with a little work) could allow this component to seamlessly work with any database. The only differentiator would be the implementation of IConnectionFactory that would have to be plugged in to create a connection bound to a particular database (Oracle, SQL, MySQL, etc.). Again, another positive side effect of this style of coding is that it allows me to easily test the behavior of this class without actually pointing it at a real database.

So, am I done with the current implementation of IEmployeeTask? Absolutely not. In my opinion, the current implementation still has too many responsibilities that should be placed in other objects (even completely different layers). Rather than drill down into more abstractions, I would rather spend the remainder of this article discussing the wiring up of all of these dependencies to one another. You can look at the code that accompanies this article to get an idea of how I cleaned up the service layer class, as well as separated responsibilities into more discrete layers.

Gluing It All Together
With all of these abstractions and dependencies being injected left, right, and center, some of you might be asking the question, "Who injects the dependencies?" I'll revisit the presenter and the accompanying web page. Remember the constructor for the presenter:

public ViewEmployeesPresenter( IEmployeeView view, IEmployeeTask task)

I can't construct the presenter without giving it both the view it is working with and the service layer it makes requests of. This poses a problem for me because the code-behind for the web page needs to instantiate the presenter that will work with it (there are other solutions to this that are outside the scope of this article):

presenter = new ViewEmployeesPresenter(this);

This would be fine if the presenter had a dependency only on the view. Unfortunately, it does not. The presenter must have both of its dependencies satisfied at the time of creation. A quick way to solve this problem would be to add a reference from the web project to the service layer project, and then do this in my code-behind for the web page:

presenter = new ViewEmployeesPresenter( this, new EmployeeTask());

Unfortunately, this causes the view to not just be responsible for creating its presenter, it also now has to create and be coupled to the dependencies the presenter is reliant on. That seems to defeat the purpose of going down this road in the first place.

You can solve this problem in a multitude of ways starting from simplistic and "coupled" to more involved and loosely coupled. I'll start off by examining the simplistic approach.

I want to ensure that the only thing the web page needs to do to construct the presenter is:

presenter = new ViewEmployeesPresenter(this);

To do this I will take advantage of constructor chaining to offer a simple constructor that the view can consume. This "convenience" constructor will call into the "greedy" constructor (the one that requires all of the dependencies) providing it with whatever it needs:

public ViewEmployeesPresenter( IEmployeeView view):this(view, new EmployeeTask()) { } public ViewEmployeesPresenter( IEmployeeView view, IEmployeeTask task)

This frees the view from needing to know anything about any dependencies (other than itself) that the presenter requires. This is a simple solution, and it introduces coupling between the presenter and a particular implementation of one of its dependencies. However, the coupling is not terrible as it only occurs in the convenience constructor. Everywhere else in the presenter it interacts with its dependency by means of the interface. The coupling exists because now the presenter is responsible for creating its dependency (an IEmployeeTask implementation). Of course, being pragmatic, if you were trying to introduce the concepts of dependency injection and dependency inversion into your own applications, this would allow you a good starting point—with an acceptable level of coupling.

However, if you want to ensure that classes with dependencies are in no way coupled to implementations of those dependencies, you can utilize the features of a service locator.



Comment and Contribute

 

 

 

 

 


(Maximum characters: 1200). You have 1200 characters left.

 

 

Sitemap