Basic Design Patterns and Groups
Design patterns fall into several groups based on the type and aims of the pattern. For example, some patterns provide presentation logic for displaying specific views that make up the user interface. Others control the way that the application behaves as the user interacts with it. There are also groups of patterns that specify techniques for persisting data, define best practices for data access, and indicate optimum approaches for creating instances of objects that the application uses. The following list shows some of the most common design patterns within these groups:
- Presentation Logic
- Model-View-Controller (MVC)
- Model-View-Presenter (MVP)
- Use Case Controller
- Host or Behavioral
- Publish-Subscribe / Observer
- Plug-in / Module / Intercepting Filter
- Service Agent / Proxy / Broker
- Provider / Adapter
|Figure 1. The Model-View-Controller and Model-View-Presenter Patterns: These patterns separate the data held by the Model from the View, linking them via a Controller or Presenter.
- Factory / Builder / Injection
The Model-View-Controller and Model-View-Presenter Patterns
The Model-View-Controller (MVC) and Model-View-Presenter (MVP) patterns improve code reusability by separating the three components required to generate and manage a specific user interface (such as a single web page). The Model contains the data that the View (the web page) will display and allow the user to manipulate. The Controller or Presenter links the Model and the View, and manages all interaction and processing of the data in the Model (see Figure 1).
In the MVC pattern, user interaction with the View raises events in the Controller, which updates the Model. The Model then raises events to update the View. However, this introduces a dependency between the Model and the View. To avoid this, the MVP pattern uses a Presenter that both updates the Model and receives update events from it, using these updates to update the View. The MVP pattern improves testability, as all the logic and processing occurs within the Presenter, but it does add some complexity to the implementation because updates must pass from the Presenter to the View.
|Figure 2. The Provider and Adapter Patterns: These patterns provide ways for otherwise incompatible components to interact.
The Provider and Adapter Patterns
The Provider and Adapter patterns allow otherwise incompatible classes to work together by converting the interface of one class into an interface expected by the other. In more practical terms, these patterns provide separation between components that allows behavioral changes to occur without prior knowledge of requirements. The application and any data sources it uses, outputs it generates, or classes it must interact with, can be created independently yet still work together (see Figure 2).
The Provider pattern separates source data from data processing objects and the application. It allows application code to be independent of the data source type and data format. A Provider component or service exposes standard methods that the application can call to read and write data. Internally, it converts these calls to the equivalents that match the data source, letting the application work with any source data type (such as any kind of database, XML document, disk file, or data repository) for which a suitable provider is available.
The Adapter pattern has the same advantages, and works in a similar way. Often, the target of an Adapter is some kind of output. For example, a printer driver is an example of an Adapter. ASP.NET itself, and other frameworks such as Enterprise Library, make widespread use of the Provider and Adapter patterns.
|Figure 3. The Service Agent, Proxy, and Broker Patterns: These patterns remove dependencies between a service and a client by using intermediate brokers.
The Service Agent, Proxy, and Broker Patterns
Various patterns exist that remove dependencies between a client and a service by using intermediate brokers. There are many different implementations of the basic pattern, some of which use an extra service-agent logic component to connect the client with the local proxy or gateway interface (see Figure 3).
The aim of all these patterns is to allow remote connection to, and use of, a service without the client having to know how the service works. The service exposes a contract that defines its interface, such as a Web Service Description Language (WSDL) document for a Web service. A client-side proxy or gateway interface uses the contract to create a suitably formatted request, and passes this to the service interface. The service sends the formatted response back through its gateway interface to the client proxy, which exposes it to the client. In effect, the client just calls the service methods on the client proxy, which returns the results just as if the service itself were a local component.
In the Service Agent pattern, an extra component on the client can perform additional processing and logic operations to further separate the client from the remote service. For example, the Service Agent may perform service address lookup, manipulate or format the client data to match the proxy requirements, or carry out any other kind of processing requirements common to different clients that use the service.
|Figure 4. The Repository Pattern: This pattern connects applications to data repositories, isolating the applications from having to know the storage mechanism or format.
The Repository Pattern
The Repository pattern virtualizes storage of entities in a persistent medium, such as in a database or XML file. For example, a repository may expose database table data as strongly typed Customer and Order objects rather than data sets or data rows. It effectively hides the storage implementation from the application code, and lets applications use a common set of methods without requiring knowledge of the storage mechanism or format. Often, the repository uses a series of providers to connect to the source data (see Figure 4).
The Singleton Pattern
The Singleton pattern defines the creation of a class for which only a single instance can exist. It is useful for exposing read-only data, and static methods that do not rely on instance data. Rather than creating an instance of the class each time, the application obtains a reference to an existing instance using a static method of the class that implements the Singleton pattern.
If this is the first call to the method that returns the instance, the Singleton creates an instance, populates it with any required data, and returns that instance. Subsequent calls to the method simply return this instance. The instance lifetime is that of the application domain—in ASP.NET this is usually the lifetime of the domain Application object.