Software architects generally think in terms of high-level abstractions rather than low-level programming details. Representing a system in terms of high-level abstractions promotes understanding of the system and reduces its perceived complexity. One such set of abstractions is software design patterns. They have been successfully applied in the past to simplify and solve recurring problems in software design.
Given the above, it comes as no surprise that many popular software libraries make extensive use of design patterns so that the APIs can be abstracted out at a high level for the end programmer. The .NET Framework Class Library (FCL) is no exception. Since the FCL builds on the strengths of Microsoft's experience with developing software libraries, one can assume that instances of design patterns found in the FCL are fairly appropriate usages of these patterns. This article describes some instances of a commonly occurring design pattern in the FCL: the Factory Method design pattern.
Related Reading .NET Framework Essentials
Table of Contents
Index Sample Chapter |
A detailed description of the Factory Method design pattern can be found elsewhere, so I will not try to describe it here. Suffice it to say that this pattern consists of two class hierarchies, one of Products, and one of Creators. Each ConcreteCreator
class creates instances of specific ConcreteProduct
classes using a factory method.
Factory methods are sometimes a more flexible way to instantiate a class than directly calling the constructor of the class, for the following reasons:
The FCL uses factory methods to its advantage in a number of places. Some of them are discussed below.
System.Collections.IEnumerable
The Iterator
interface traverses a collection of objects. The interface aims to create a way to access the elements in a collection without exposing the internal structure of the collection. One way to implement this interface would be to have every collection class return an iterator object supporting a specific interface for iterating over collections of that particular type only. However, using this approach, one usually ends up exposing the internal structure of the collection being traversed. The FCL uses a better approach: it uses a factory method to return a polymorphic instance of the appropriate iterator class. All iterators returned by this factory method support a common interface for enumerating over all collection classes without exposing the internal structure of the collection being traversed. This has the added benefit of allowing changes to be made to the collection without requiring a change in the client code.
By specifying a GetEnumerator
factory method in the IEnumerable
interface and by having all collection classes implement this interface, the framework exposes one interface for obtaining an enumerator for a collection. ArrayList
is one such class that implements the IEnumerable
interface. ArrayList.GetEnumerator
returns an IEnumerator
object capable of enumerating over the elements in the ArrayList
. Figure 1 shows the class hierarchy where the Iterator
interface uses the Factory Method pattern.
Figure 1. Factory Method pattern for obtaining an enumerator for an ArrayList object |
Since an iterator must have knowledge of the internal structure of the class over which it iterates, it is best to let every class provide its own iterator. IEnumerable
classes provide their own iterators using GetEnumerator
. In Figure 1, IEnumerable
(the Creator) defines the interface by which an IEnumerator
(the Product) is returned to the client. A ConcreteCreator
(ArrayList
) can then be called to return a ConcreteProduct
(ArrayListEnumeratorSimple
, a private inner class of ArrayList
), which is an IEnumerator
object capable of iterating over an ArrayList
. Clients are required to refer to the returned object by the interface IEnumerator
.
System.Net.WebRequest
WebRequest
serves as a convenient base class for the .NET Framework's request/response model for accessing data from the Internet. This class encapsulates the details of connecting to the server, sending the request, and receiving the response. This means that an application can participate in request/response transactions in a protocol-agnostic manner using instances of the WebRequest
class, while protocol-specific classes derived from WebRequest
carry out the details of the request.
The static factory method WebRequest.Create
creates protocol-specific descendants of WebRequest
using the value of the URI passed in as argument. For example, when a URI beginning with "http://" is passed, an HttpWebRequest
object is returned; when a URI beginning with "file://" is passed, a FileWebRequest
object is returned.
By default, the .NET Framework supports "http://", "https://", and "file://" URI schemes. This is easily verified by looking at the
section of the machine.config file in the .NET Framework installation's CONFIG directory:
This section implies that System.Net.HttpRequestCreator
is responsible for creating WebRequest
objects for request URIs beginning with "http" and "https", and System.Net.FileWebRequestCreator
is responsible for creating WebRequest
objects for request URIs beginning with "file". Both of these classes implement the System.Net.IWebRequestCreate
interface, which contains only one public method:
>Figure 2. Factory Method pattern used for creating a WebRequest instance for "http"- and "https"-type URIs |
Figure 2 illustrates the Factory Method pattern used to obtain a WebRequest
instance for "http://"- and "https://"-type URIs. WebRequest.Create
delegates creation of the appropriate WebRequest
(the Product) object to an IWebRequestCreate
object (the Creator). HttpRequestCreator
(the ConcreteCreator
) is then called to return an instance of HttpWebRequest
(the ConcreteProduct
). This design is interesting because it contains two Creators — WebRequest
and IWebRequestCreate
. Even though WebRequest
is the Creator visible to the client, it is IWebRequestCreate
that decides which derived object to return. The IWebRequestCreate
interface is internal to the System.Net
assembly by intention, so the only way to create an instance of WebRequest
is by calling WebRequest.Create
.
WebRequest.Create
is a parameterized factory method -- it takes a parameter that identifies the type of object to create, and all objects created are of type WebRequest
.
System.Security.Cryptography
ClassesThe .NET Framework contains a rich and extensible collection of cryptography classes that you can use within your own programs, right out of the box. Cryptography classes are part of the System.Security.Cryptography
namespace. These classes use the Factory Method pattern to decouple the choice of algorithms used from their specific implementations.
SymmetricAlgorithm
, AsymmetricAlgorithm
, and HashAlgorithm
are the three roots of the class-inheritance hierarchy in the cryptography framework. These are abstract classes from which specific implementations of various encryption algorithms are derived. Each of these classes supports a static factory method called Create
, which creates a particular instance of the cryptography class based on the type of algorithm requested. For example, the following line will instantiate a SymmetricAlgorithm
-derived class called DESCryptoServiceProvider
, which is the default implementation of the Data Encryption Standard (DES) algorithm in the .NET Framework.
The mapping between the string arguments and the instantiated classes can be found here.
Like WebRequest.Create
, SymmetricAlgorithm.Create
is a parameterized factory method; it takes a parameter that identifies the type of object to create, and all objects created are of type SymmetricAlgorithm
. The use of a parameterized factory method here is important because it provides opportunities for extending the cryptography framework. For example, by adding a mapping for the RC5 algorithm (which does not currently exist in the .NET Framework SDK) that returns an instance of, say, RC5CryptoServiceProvider
, one can add an RC5 implementation to the existing framework, and instantiate it using the following line:
System.Security.Policy.IIdentityPermissionFactory
The code-access security model implemented by the CLR requires every assembly to pass through a security checkpoint at the time of loading. This involves granting privileges to the code based on the origin of the assembly, digital signatures on the assembly, custom evidence attached to the assembly, requests made by the assembly, and so on. Evidence is presented by the assembly in the form of a System.Security.Policy.Evidence
object, which is a collection of evidence objects (not Evidence
objects) like System.Security.Policy.Url
, System.Security.Policy.Zone
, etc.
Each evidence object can possibly create an identity permission that is added to the grant set of the assembly. Therefore, for all pieces of evidence that implement the IIdentityPermissionFactory
interface, the corresponding identity permission is obtained and added to the grant set of the assembly.
Figure 3. Obtaining a collection of IPermission objects for a collection of evidence objects |
Figure 3 shows the class diagram for a case where an assembly presents only a System.Security.Policy.Url
object, which is evidence of the URL from where the assembly originates. This evidence object is encapsulated in a System.Security.Policy.Evidence
collection, which is then passed to the CreateIdentityPermission
method of IIdentityPermissionFactory
. The CreateIdentityPermission
method has the following signature:
The .NET security framework calls the Factory Method CreateIdentityPermission
on the appropriate implementation of IIdentityPermissionFactory
to get an IPermission
object that represents that piece of evidence. If multiple evidence objects are involved, then during policy resolution the runtime calls CreateIdentityPermission
on all evidence objects that implement IIdentityPermissionFactory
and grants the resulting identity permissions to the appropriate assembly in the form of a PermissionSet
object, which is simply a collection of IPermission
objects.
The Factory Method pattern used in the above framework abstracts out the policy resolution process to the highest level, where the client (typically the SecurityManager.Resolve
method, as shown below) takes in a System.Security.Policy.Evidence
object and gets back a PermissionSet
object.
The mechanism of identifying the evidence types and creating IPermission
objects representing those evidence types is completely transparent to the client.
Several instances of the Factory Method pattern can be found in the ASP.NET HTTP pipeline. The ASP.NET HTTP pipeline is a set of classes (in the System.Web
namespace) that a web server uses to process an incoming HTTP request and return a response to the client. The pipeline takes care of session management, application pooling, caching, security, etc.
At every point in the pipeline, the objective is to advance the request processing by one step by either identifying the objects that can handle the incoming request, or by forwarding the request to objects capable of handling the request. Factory methods come into play when different types of objects need to be instantiated, based on the type of incoming request.
System.Web.HttpApplicationFactory
The entry point in the pipeline is the HttpRuntime
object, which creates an instance of HttpContext
for the particular request. HttpRuntime
does not try to determine the type of HttpApplication
object that will handle the request. Instead, it calls the static factory method HttpApplicationFactory.GetApplicationInstance
, passing it the HttpContext
instance just created. HttpApplicationFactory
is an undocumented class that contains the logic required to determine the HttpApplication
object capable of handling an incoming request. GetApplicationInstance
uses the HttpContext
instance to determine the virtual directory (i.e., application) that this request was sent to. If the virtual directory has been called before, then the HttpApplication
object (or a derived ASP.Global_asax
object, if Global.asax is defined) is returned from the pool of applications. Otherwise, a new HttpApplication
object for that virtual directory is created and returned. Figure 4 shows the class diagram for instantiating an HttpApplication
object capable of handling the request.
Figure 4. Fetching the appropriate HttpApplication object |
HttpApplicationFactory.GetApplicationInstance
is a parameterized factory method. It takes a parameter that identifies the type of product to create, and all products created are of type HttpApplication
.
System.Web.IHttpHandlerFactory
Moving farther along in the pipeline, the HttpApplication
instance just created needs the object that can handle the type of resource requested. This object is called a handler. To look up the proper handler, the HttpApplication
first determines the factory that can create the handler. It does that by looking up the
section of the machine.config file. If it's not found in machine.config, it looks up the application's web.config file, using the inherited configuration model. The
section in these config files lists the handlers currently registered for the application. A part of this section is reproduced below.
This section shows the mapping between the type of resource requested and the class capable of creating a handler for that resource. If an .aspx page is requested, the System.Web.UI.PageHandlerFactory
class will be called. Once this class has been located, HttpApplication
invokes the GetHandler
factory method on the IHttpHandlerFactory
interface to retrieve a new instance of the handler class. All such factory classes must implement the IHttpHandlerFactory
interface. These factory classes have no behavior except to dynamically manufacture new IHttpHandler
objects using the GetHandler
method. This method returns an IHttpHandler
object, which in this example is the System.Web.UI.Page
-derived class created from the .aspx file. For an .aspx file called SamplePage.aspx, the compiled class will be called ASP.SamplePage_aspx
, as shown in Figure 5. This class serves as the endpoint for the request, and is responsible for populating the response buffer for that particular request.
Figure 5. Factory Method pattern used for obtaining the appropriate IHttpHandler object for a resource |
IHttpHandlerFactory.GetHandler
is a classic example of the Factory Method pattern, where IHttpHandlerFactory
(the Creator) decides which IHttpHandlerFactory
-derived object to create, PageHandlerFactory
(the ConcreteCreator
) creates ASP.SamplePage_aspx
(the ConcreteProduct
), which is returned as an IHttpHandler
(the Product) object.
The Factory Method pattern is probably the most commonly found design pattern in the FCL. This article has presented a few notable instances of the use of this pattern in the FCL. If you begin to explore, you will probably find many more instances. Identifying those instances and understanding the motivation for their use can provide useful insights into your own designs.
Amit Goel has been developing object-oriented applications for several years. You can learn more about him at www.amitgoel.com.
Return to ONDotnet.com