![]() | |
Figure 1. A Simple Screen: This simple screen looks like it should be easy to build, right? |
|
![]() | |
Figure 2. Layer Diagram: Here‘s a proposed high-level diagram for the separate layers. |
public partial classViewEmployeesWithAdditionOfPresenter : Page,IEmployeeView{private ViewEmployeesPresenterLowCohesion presenter;protected override void OnInit(EventArgs e){base.OnInit(e);presenter = newViewEmployeesPresenterLowCohesion(this);}public IList Employees{set{this.employeesRepeater.DataSource = value;this.employeesRepeater.DataBind();}}}
Compared to Listing 1, the difference here is night and day. If you are not familiar with the passive view pattern, here‘s a quick description: public interface IEmployeeView{event EventHandler Load;bool IsPostBack { get; }IList<IEmployee> Employees { set; }}
Pretty simple. Notice that the Load event is defined on the View interface, but you probably did not see an explicit implementation in the code-behind for the web page. This is because all web pages already define a Load event (with the same delegate signature), which satisfies the requirements of the interface. The same goes for the IsPostback property (already satisfied by the Page class). So why introduce an interface at all? The reason is that by coding to an interface (or an abstraction), the presenter can now talk to any object that implements the interface, whether it is a Windows Form, a mobile web control, or a web page. The presenter does not care about the actual implementation because it will always be talking to that implementation through an abstraction—the interface. This point demonstrates and introduces the importance of the dependency inversion principle, which can be described simply as:"High-level components should not depend on low-level components; they should both depend on interfaces."I will take that principle and utilize it to further clean up the code in the presenter.
using (connection = newSqlConnection(ConnectionString)){SqlCommand command = connection.CreateCommand();command.CommandText = "SELECT * FROM Employees";command.CommandType = CommandType.Text;connection.Open();using (SqlDataReaderreader = command.ExecuteReader(CommandBehavior.CloseConnection)){DataTable results = new DataTable();results.Load(reader);return results;}}
The preceding code couples the presenter to SqlConnection, SqlCommand, and SqlDataReader objects. In reality, worse than the coupling is the fact that this functionality does not really belong in the presentation layer of a project, because it still unnecessarily couples my presentation layer to the underlying physical database that is serving data to this application. public interface IEmployeeTask{IList<IEmployee>GetAllEmployees();}
Yes, it‘s that simple. Again, following the dependency inversion principle leads me to believe that the presenter now has more than just a dependency on the View. Prior to the introduction of the service layer, the presenter was responsible for work that will (eventually) be pushed down into a service layer. The beauty of coding to abstractions is that the presenter has to talk only to a contract. At compile time the presenter does not know (or care) whether that contract is implemented. This allows me to complete the code for my presenter without the need for an actual concrete implementation of the service-layer component to even exist. Listing 3 shows the presenter refactored by introducing a dependency on a lower-layer component. publicViewEmployeesPresenter(IEmployeeViewview, IEmployeeTask task)
Even though the presenter has its own cohesive set of responsibilities, it cannot accomplish its responsibilities without leaning on its dependencies. It just so happens that those dependencies are provided to it at the time of creation. This is a type of dependency injection called constructor-based dependency injection. [Test]public void ShouldSubscribeToViewEventsOnConstruction(){MockRepository mockery = new MockRepository();IEmployeeView mockView = mockery.CreateMock<IEmployeeView>();IEmployeeTask mockTask = mockery.CreateMock<IEmployeeTask>();mockView.Load += delegate { };LastCall.IgnoreArguments();mockery.ReplayAll();ViewEmployeesPresenter presenter = newViewEmployeesPresenter(mockView, mockTask);mockery.VerifyAll();}
The preceding code uses a mock object framework called Rhino Mocks and the NUnit unit testing framework. (As a practitioner of TDD, I would usually write this test first to drive out the functionality of the presenter; however, for this article I chose to not cloud the topic with another conversation about TDD!) You can find the accompanying code that makes this test pass in the presenter class itself: public ViewEmployeesPresenter(IEmployeeView view,IEmployeeTask task){this.view = view;this.task = task;HookupEventHandlersTo(view);}private void HookupEventHandlersTo(IEmployeeView view){view.Load += delegate {LoadEmployees(); };}
Notice that the constructor calls the HookupEventHandlersTo method, which in turn subscribes to the Load event defined by the View interface. 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 EmployeeTaskLowCohesionNoDependencyInversion(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. 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. 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. Dependency Injection with Service Locators To completely eliminate the need for the presenter to be aware of which implementation of IEmployeeTask it should use, you must add a new element into the mix. In the realm of dependency injection, a service locator is simply an object that knows how to retrieve dependencies for other objects. In this scenario, it would be the role of the service locator to find an implementation of IEmployeeTask that the presenter can work with. All of you who have been reading along probably know the answer to the question, "Does this mean that my presenter will now have a dependency on this service locator?" Absolutely. Then you might ask, "Does this mean I should start changing the constructor of my presenter to also allow it to accept a service locator?" You could do that. Unfortunately, if other classes down the road want to utilize the services of the locator to resolve their dependencies, they too would require a constructor that allowed them to accept an interface to the service locator. This seems like a little too intrusive to the architecture and more work than is necessary. The solution I am going to propose is one that you can use immediately if you want to start utilizing service locators in your own projects. It is also a solution that can scale when you start using full-blown dependency injection frameworks like Windsor Castle, a popular, open-source dependency injection framework. I am first going to create an interface for the service locator: The preceding code uses generic methods to avoid the need to cast when invoking the locator from client methods. I stated that I want existing classes to be able to consume the functionality provided by the service locator without a need to have an explicit parameter dependency on it. To accomplish this I will use a static class that will delegate all of its calls to any particular implementation of the service locator interface: Notice that the DependencyResolver class has a method called RegisterResolver which is passed an implementation of IDependencyResolver that it can forward its calls onto. What does this translate to from the perspective of the presenter? Instead of it needing to have knowledge of the EmployeeTask implementation of IEmployeeTask, it can now use the DependencyResolver class to locate an implementation of IEmployeeTask. This changes the constructors in EmployeePresenter from this: To this: Notice that I am still making use of the greedy constructor that requires everything that the presenter requires. I can use this constructor from a testing perspective to verify the behavior of the presenter. In the constructor that the web page uses, the presenter uses the DependencyResolver and asks it to retrieve an implementation of an IEmployeeTask. Now, nothing in the presenter couples it to the EmployeeTask component!I chose to couple the presenter to the service locator by using the static DependencyResolver class. Someone out there right now is screaming, "static classes are evil!" In addition, lots of people scream, "singletons are evil." In either case, they are not evil, as long as they allow for testability, which is typically not easy to do with traditional singleton or static class implementations. This scenario makes testability easy because the DependencyResolver static class does nothing more than delegate its work to an IDependencyResolver implementation (which you can easily fake at test time). The advantage of using the interface (IDependencyResolver) is that when I am first starting down the service locator route, I may be content with creating my own service locator that gets configured at application startup. Listing 5 shows the code for such a locator. Here‘s an example that configures such a locator in a class invoked at application startup: Notice that I explicitly tell the service locator when asked for implementations of IEmployeeTask to return the EmployeeTask object. This particular implementation also enforces the EmployeeTask to be a singleton in this application, even though it is not explicitly marked as a singleton. The final step registers the service locator with the DependencyResolver so that all clients can access its functionality.If you want more functionality out of your service locator you may not want to code it yourself. By using the IDependencyResolver interface, you can easily switch to an implementation that leverages already existing dependency injection frameworks. Listing 6 shows an example of an IDependencyResolver implementation coded to work with Windsor Castle. The value of coding to interfaces means that when (and if) I switch to Windsor (or another dependency injection framework), very little of my client code should change. In fact, the only change required to use Windsor is to change the ApplicationStartupTask class as follows: The advantage of using a full-featured framework such as Windsor is that there is no longer any code (not even in ApplicationStartUp) tied to particular implementations of dependencies. Objects that need dependencies can still ask the DependencyResolver class to retrieve them and the DependencyResolver will use whatever implementation of IDependencyResolver was provided to it to satisfy the request.In the downloadable source code accompanying this article, you can see how I configure the Windsor container using Binsor, a great tool for configuring Windsor without XML files. Ayende Rahien developed Binsor and it allows me to configure dependencies using configurations stored outside of the application. Wrapping Up I have covered a lot of ground in this article. I started with a single-tiered application that breaks many of the best practices that many of you are already well aware of. I introduced a layered architecture and some refactoring techniques that drove me to use the dependency inversion principle. You can see the benefit of coding to abstractions vs. implementations. To top it off, I introduced the concepts of dependency injection and service locators as tools to help you realize the benefit of coding to abstractions. You now have another arsenal of tips and techniques that you can start applying to realize more loosely coupled solutions in your application architectures. ![]() |
![]() ![]() |