1. Introduction
In the previous part of the article I showed the first part of most important patterns and practices used in the Composite Application Library (CAL). In the second part I will show you the second group – the Modularity patterns.
As a whole the patterns used in CAL can be separated in three main groups:
- Composite User Interface patterns (part 1)
- Composite
- Composite View
- Command
- Adapter
- Modularity patterns (part 2)
- Separated interface and Plug In
- Service Locator
- Dependency Injection
- Event Aggregator
- Façade
- Registry
- Testability patterns (part 3)
- Inversion of control
- Separated presentation
Before walking through the patterns from this group lets explain the “Modularity” term. The Modularity is an important characteristic of the CAL. Modularity is designing a system that is divided into a set of functional units, which are called modules. All modules are composed into a larger application. Each module is independent unit that may contain different components such as views, business logic, services, etc. For example, consider a hospital software program. Each doctor can access a variety of functions according to its privileges. The user can add new clients, make its schedule, make invoices, etc. However, behind the scenes, each piece of this program is an independent module that may evolve separately.
If the modularity principle allows you to locate and load modules at run time in a loosely coupled way, the following patterns offer you even greater opportunities to create a loosely coupled architecture.
3.1.1. Separated Interface
The design pattern known as Separated Interface (introduced by Martin Fowler) is an approach for reducing coupling in one application. It achieves that by separating the interface definition and the implementation in different packages. Thus the end client depends only on the interface and it is completely unaware about the concrete implementations. For example if you create a new Silverlight application using the Composite Application Library you may need to create new module(s). Then each module should implement the IModule interface which definition is part of the library.
One very famous usage of the Separated Interface pattern is when you need to manage a circular reference in your code. For example you are creating a video store application. Each video has a genre. When you add a new genre you want to be sure that it has not been added into your database. All your layers are separated in different projects (assemblies). The Data Access already relies on your domain objects, because these are the objects (movie, genre, customer, etc.) that are returned from its methods. At the same time you want to call methods of the data access from your domain model (you want to see if the current genre exists in the database). You cannot add a reference to the data access because it would create a circular reference. To solve this problem you should put all methods needed by the domain model into a separate interface, which you can place in the domain package. A visual representation of the pattern can be seen on the next diagram.
3.1.2. Plug – In
The Plug-In pattern is a software practice for extending the behavior of a class. It allows concrete implementation of a class to be determined at run time instead of at compilation time. For example in the Composite Application Library, this is handled by the ModuleInitializer.
There are several approaches for extending the functionality of a class. One of them is the usage of inheritance. The problem with this approach is that sometimes the derived class has unrelated behavior extensions. Another way to extend the class behavior is the using of configuration. In this approach the class has some primitives with which the user is able to configure the behavior of the class. The problem with this solution is that the behavior extensions are limited by the configuration abilities that the class provides.
The Plug-In pattern derives its name from the fact that it plugs – into a core class some additional behavior. It creates an object instance of an interface at run time. The pattern differs from using class inheritance (where behavior is altered or overwritten), or configuration (where behavior modification is limited to the configuration capabilities). With the Plug-In pattern, the modified behavior (the plug-in) connects to an abstract partial class, which, in turn, connects to the core class. The plug-in uses this interface to implement methods called by the core class and can also call new methods at the core class. A simple diagram can be seen on the next figure.
The Service Locator pattern is a variety of the Inversion of Control pattern (which is described later in the article). It is also considered as an alternative of the Dependency Injection pattern (also later described in the article). The Service Locator pattern allows classes to locate specific services they are interested in without the need to know about their implementations, or who implements the services. In the CAL a simple example for the Service Locator can be seen in the ModuleInitialize which resolves individual IModules objects.
The Service Locator pattern is extremely important in the world of distributed applications and service oriented architectures, where the need of transparently locating the business components and services is a vital necessity.
For example, let’s examine the problem shown on the next diagram.
You have a class that has a direct dependency on services whose concrete type is specified at design time. In our example, the ClientClass has reference to the Service1, Service2 and Service3. This approach causes the following problems:
- Your class is tightly coupled.
- In order to update the dependencies, you have to change your class code.
- The concrete implementations of the dependencies must be available at compile time.
- Your class contains code for creating, locating, and managing its dependencies, which is not possible to be reused.
- Your ClientClass is impossible to be tested, because it has a direct reference to its dependencies, which cannot be replaced with stubs or mocks.
The solution: see the next diagram.
You need to create a service locator that contains references to the services and encapsulates the logic to locate them. After the service is registered, then the locator can find the service. An important characteristic is that the service locator does not create an instance of the services, it only locates them. The service locator should provide a way to locate the service without to know the concrete type. The most straightforward way to do this is to provide a string key or to use a service interface type. There are a few ways to implement the Service Locator pattern. You can create a global singleton instance which holds references to the services.
The advantages of the Service Locator pattern are:
- It decouples your classes from their dependencies, so these dependencies can be modified or replaced with minimal changes to your classes.
- Your classes depend on classes whose concrete implementation is unknown at compile time.
- You are able to test your classes in isolation.
- Your classes are not responsible for locating and managing the dependencies.
The disadvantages of the Service Locator pattern are:
- There are more elements (classes) to manage.
- More complexity in the source code. Your source code is more difficult to understand.
- An additional code is needed to be written to create the service locator.
The Dependency Injection pattern is very similar to the Service Locator. It is also variation of the Inversion of Control pattern. The Dependency Injection pattern allows classes to locate specific services they are interested in without needing to know about their implementations, or who implements the services.
So let’s look again at the problem we have in the Service Locator section.
Again we want to find an approach which decouples the Client Class from its dependencies. The solution is shown on the next diagram.
As you can see you don’t have to instantiate the dependencies explicitly in your class. Instead, declaratively express dependencies in your class definition. Use a Builder to obtain valid instances of your object’s dependencies and pass them to your object during its creation or initialization. There are two types of injection:
- Constructor injection – in this case you use parameters of the object’s constructor to inject it with its dependencies.
- Setter injection – in this case the object exposes setter properties (or methods) which are used from the builder to pass the dependencies to the object during its initialization.
The pros and cons are absolutely the same as at the Service Locator, so I won’t repeat them.
The Event Aggregator pattern is pretty similar to the Facade, with the only difference that it is focused only on observer relationship. Imagine we have a system with lots of objects, and every object is a potential source of events. If the client wants to subscribe to all events, he has to register for each object individually, and if each object has multiple events then event handler is required for each of them. Of course this will lead to a big complexity. The solution is to use the Event Aggregator pattern, which acts as a single source of events for many objects. It registers for all the events of the many objects allowing clients to register with just the aggregator.
The conceptual view of the Event Aggregator pattern can be seen on the next diagram.
As an example for that pattern in the Composite Application Library you can see the EventAggregator and the CompositePresentationEvent classes.
The Facade is one of the most used patterns. It provides a unified interface to a set of interfaces in a subsystem. Facade defines a higher-level interface that makes the subsystem easier to use. You can see its diagram on the next figure.
Or in other words, you should use the Facade pattern when you want to simplify a more complex interface, or set of interfaces, to ease their use, or when you want to isolate access to those interfaces.
The Registry pattern allows you to navigate or locate one or more objects from a well-known object. When you want to find an object you usually start with another object that has a reference to it and use its association. For example if you want find all order for a specific customer, you get the customer object and invoke its method GetOrders() to obtain the orders. However sometimes you don't have a reference to an appropriate object. On the contrary you have only some identificator (ID) but not a reference. In this case you need some kind of lookup method – a finder. Here is the key role of the Registry, which is a well-known (global) object which other objects use to find common services and objects.
An example from the Composite Application Library is the IRegionViewRegistry interface and RegionViewRegistry class, which define a registry used to associate region names to the view types created when those regions are loaded.
4. References
http://msdn.microsoft.com/en-us/library/dd139883.aspx
http://codebetter.com/blogs/jeremy.miller/archive/2005/09/13/131897.aspx
http://msdn.microsoft.com/en-us/library/cc304894.aspx
http://www.martinfowler.com/eaaDev/EventAggregator.html
http://msdn.microsoft.com/en-us/library/cc304779.aspx