Object Creational Patterns and Instantiation
 
Published: 13 Jun 2007
Abstract
This article will discuss the various ways an object can be created, explaining the more dynamic forms of object creation. It will then illustrate the various forms of creational patterns that a developer can use to setup his or her application architecture.
by Brian Mains
Feedback
Average Rating: This article has not yet been rated.
Views (Total / Last 10 Days): 42013/ 73

Introduction

All objects need to be created somehow. The question most people have is what is a good strategy for doing so?  Should the object be directly instantiated?  Should it be loaded in a special way, like using one of the many design patterns?  How do you instantiate an object dynamically, or what is a good way to reference the object?  All of this will be discussed in this article.

Instantiation

Whenever an object is created, it is instantiated in several ways.  The most common way to instantiate an object is using the new keyword.

Listing 1

DataTable table = new DataTable();

Using some of the design patterns, which we will talk about in a moment, instantiate objects using the new keyword.  However, there are dynamic ways to create an object, such as the Activator class's CreateInstance and CreateInstanceFrom methods.  These methods have various overloads.  One of the overloads is a generic method that takes the type to instantiate.  Another takes a Type object and instantiates it using this type.  If a more dynamic reference is needed, the method can take an assembly name and the name of the type to instantiate.  Note, on some overloads the method returns an ObjectHandle and not an object.  To get the object reference, call the Unwrap method.  The following is a few variations.

Listing 2

MyClass classInfo = Activator.CreateInstance<MyClass>();
 MyClass classInfo = (MyClass)Activator.CreateInstanceFrom(
 "MyComponentLibrary""MyComponentLibrary.MyClass").Unwrap();
 Type type = Type.GetType("MyComponentLibrary.MyClass,MyComponentLibrary");
 MyClass classInfo = (MyClass)Activator.CreateInstance(type);

If the object being instantiated does not have a default parameterless constructor, then there is an overload that takes an object parameter array, representing the values of the objects defined in the constructor.  The types of these objects have to match the parameter types for the specific constructor.  This approach is more synonymous with using the ConstructorInfo object, a part of the Reflection API.  Using Reflection, a type can access the constructor through the GetConstructor() or GetConstructors() methods.  This object contains the definition and parameter types of the constructor, and an object reference can be created using the Invoke method.

Listing 3

MyClass classInfo = null; 
 ConstructorInfo constructor = type(MyClass).GetConstructors()[0]; 
 if (constructor != null) 
 classInfo = (MyClass)constructor.Invoke(new object[] { "Some Name", 1, "Sidney" }); 

There are varying thoughts about the cost that reflection has in an application. Some say that using reflection in an application does have a significant performance hit, while others say that in reality the hit is negligible and is worth the cost to gain some of the added capabilities that reflection has in the .NET Framework.

Creational Patterns

Armed with the above type-instantiation information, we can apply this to patterns and how they are used.  Especially in .NET applications, classes can make use of dynamic references, which are most often defined in the configuration file.  Within this file it is possible to specify a string containing the type name and assembly, similar to how you see it already in the .NET Framework.  Using the Type.GetType method, it is possible to obtain a reference to the type, if the framework can resolve it.  And from this, we have our basis for dynamically retrieving the object reference.

Now we begin to look at the creational patterns that are available.  If you are aware of the book "Design Patterns" by Gamma et. al, this book specifies five creational patterns that are most widely used when designing software.  We will look at some of those, and perhaps a few others.  Note, most patterns avoid directly instantiating an object through the constructor, and so the constructor is often declared private or internal.  It is up to you to determine whether you want to expose the constructor, or to instantiate through another means.  Let us begin by looking at the design patterns.

Factory Pattern

The factory pattern is responsible for performing the direct instantiation of an object.  It can take some sort of designator: a string, a generic type, an enumeration, or some other key to dynamically create the reference of the object for you.  Let us take a look at an object.

Listing 4

public class Verse 
 { 
 public string Name { .. } 
 public int Number { .. } 
 public string Text { .. } 
 
 internal Verse(string name, int number, string text) { .. } 
 } 

Note that the class Verse has an internal constructor, so other classes within the Visual Studio project can instantiate it, but the general public that consumes this project cannot.  This forces any activity on this object to go through the factory.  The following is the factory definition.

Listing 5

public static class verseFactory 
 { 
 public static Verse GetVerse(string name) 
 { 
 //Access the data layer to get the specific verse by name public static VerseCollection GetVerses(object parent) 
 { 
 //Access the data layer to create a collection of verses by name 
 } 
 } 
 
 
 


The factory is a static definition; it handles performing data retrieval from the data layer, as well as the creation of the verse objects.  The method definition for GetVerses could look something like this:

Listing 6

VersesDataGateway gateway = new VersesDataGateway(); 
 DataTable versesTable = gateway.GetVerses(); 
 VerseCollection versesList = new VerseCollection(); 
 
 foreach (DataRow versesRow in versesTable.Rows 
 { 
 Verse verse = new Verse( 
 versesRow["Name"].ToString(), 
 (int)versesRow["Number"], 
 versesRow["Text"].ToString()); 
 versesList.Add(verse); 
 } 
 
 return versesList; 

Notice that the factory is handling the instantiating of the object.  Because this class would contain several methods that retrieve data from the back-end data store, I would move the verse creation capabilities into another method, but you get the idea.  This is what the factory could do to get the data from the data store.  The factory can handle more responsibility, such as updating the changes from the Verse class back to the data store, deleting items from the data store or any other responsibility you may want to give it.

However, suppose you wanted to give the factory a more dynamic functionality.  For instance, suppose you wanted to have a collection of objects that could be instantiated dynamically, based on a key value. This factory could then add/remove support to keys very easily, but how would that be implemented?  To illustrate, let us use an example. Suppose you had an evaluator factory which returned the appropriate evaluator based on a string key that was passed in.  This list of evaluators can be stored in the configuration file.

Listing 7

<evaluatorSettings> 
 <evaluators> 
 <add key="month" type="Nucleo.Evaluators.MonthEvaluator,Nucleo" /> 
 <add key="day" type="Nucleo.Evaluators.DayEvaluator,Nucleo" /> 
 <add key="year" type="Nucleo.Evaluators.YearEvaluator,Nucleo" /> 
 <add key="week" type="Nucleo.Evaluators.WeekEvaluator,Nucleo" /> 
 </evaluators> 
 </evaluatorSettings> 

If you are interested in creating a custom configuration section and their child collections, you can read my series of articles from the links below.

·         http://dotnetslackers.com/articles/customconfiguration/Custom_Configuration_Sections.aspx

·         http://dotnetslackers.com/articles/customconfiguration/Configuration_Section_Validators.aspx

·         http://dotnetslackers.com/articles/customconfiguration/Custom_Configuration_Collections.aspx

·         http://dotnetslackers.com/articles/customconfiguration/Custom_Provider_Configuration_Sections.aspx

Our factory would be able to connect to the custom configuration section and extract the object keys/types that it needs to instantiate.  Below is a possible implementation of that solution.  Note that the evaluators' collection would most likely be a static collection of evaluators, which the consumer of the factory can reference via the key.  By giving each of the evaluators a common base class, each custom evaluator can be easily referenced.

Listing 8

foreach (EvaluatorElement element in evaluatorSection.Evaluators)
{
  Type evalType = Type.GetType(element.Type);
  EvaluatorBase evalBase = (EvaluatorBase)Activator.CreateInstance(evalType);
  _evaluators.Add(element.Key, evalBase);
} 
 
 
Factory Method

Sometimes a separate factory class may not be desired, for whatever reason.  If you like to keep the logic of creating a class within the same class as the created object, or within another related class, then this situation is a possibility with the factory method. The factory method is usually implemented as a static method.  For instance, below is a use of the factory method.

Listing 9

public class DocumentViewer 
 { 
 public static DocumentViewer GetViewerInstance() 
 { 
 return new DocumentViewer(); 
 } 
 } 

The template method pattern does not have to be declared public; rather, it could be an internal way to instantiate an object within the project only. For instance, when loading data from result sets returned by the data layer, I will often use a static method to instantiate an object with data from a DataRow, or some other object.  I do this because it keeps all of the logic pertaining to that class within the class definition, which I think makes it easier to maintain.  I created an example for this below.

Listing 10

public static DocumentViewer 
 { 
 internal static DocumentViewer CreateFromData(DataRow row) 
 { 
 if (row == nullthrow new ArgumentNullException("row"); 
 
 DocumentViewer viewer = new DocumentViewer(); 
 viewer.Name = row["Name"].ToString(); 
 viewer.Size = (int)row["Size"]; 
 viewer.PPM = !row.IsNull("PPM") ? (int)row["PPM"] : 600; 
 
 return viewer; 
 } 
 } 

All of the logic dealing with DocumentViewer is within the DocumentViewer class and only internal classes from the project can create a new document viewer from a row of data. This approach may be more suitable than a full-blown factory, but if you find yourself creating several static methods to perform various operations, maybe the factory pattern would be a better solution and make it more readable.

Singleton

Sometimes you need global access to an object, because this object may contain static properties, events, or methods you may access throughout your application.  Through this static object, the application can be more easily decoupled from other related classes because more classes can interact through the singleton and not as much by referencing the other objects directly.

This is the singleton pattern; it has the benefits that it maintains its own instance and provides this central access throughout the application. The key benefit is the ability to expose events, which the other classes in a project can subscribe to by attaching their own event handlers to it.  When the event fires, all registered objects are subscribed to that event; this is similar to the Observer pattern.

How can you create a global instance?  Let us use a class called ServicesCentral, which provides access to key objects/collections throughout an application. The class definition and the singleton reference would appear as such:

Listing 11

public class ServicesCentral 
 { 
 private static readonly ServicesCentral _instance = new ServicesCentral(); 
 
 public static ServicesCentral Instance 
 { 
 get { return _instance; } 
 } 
 
 private ServicesCentral() 
 { 
 //Instantiate any collection objects here 
 } 
 } 

A static instance variable represents the ServicesCentral class, which is exposed through the Instance property. This instance is used internally to give access to the properties and methods, as we will see next. The constructor of the singleton is also marked private or protected so only the singleton can instantiate itself. Within that constructor, any of the objects are instantiated so they are available to the user of the singleton.  Let us look at a few objects that can be exposed through the singleton.

Listing 12

private MenuCollection _menus = nullprivate ToolbarCollection _toolbars = nullprivate MarkedListRepository _currentList = nullpublic static MenuCollection Menus 
 { 
 get { return Instance._menus; } 
 } 
 
 public static ToolbarCollection Toolbars 
 { 
 get { return Instance._toolbars; } 
 } 
 
 public static MarkedListRepository CurrentList 
 { 
 get { return Instance._currentList; } 
 } 
 
 private ServicesCentral() 
 { 
 _menus = new MenuCollection(); 
 _toolbars = new ToolbarCollection(); 
 _currentList = new MarkedListRepository(); 
 } 

The singleton exposes a collection of menus, toolbars, and other objects that are important to an application. The scenario above is similar to exposing an API for an application, such as Word or Excel. All of the necessary objects are instantiated in the private constructor. Because the instance is instantiated internally, all objects are referenced through the Instance property because this Instance property is the true object that holds the singleton reference.

Notice how the private variables that hold references to these objects are not static; instead, because they are exposed through the Instance property and because Instance contains a reference to the singleton object, it can access the appropriate internal variables.  In addition to existing properties, you can add helper properties/methods that are generally helpful in your application. For instance, you can add the following.

Listing 13

public static CultureInfo CurrentCulture 
 { 
 get { return Thread.CurrentThread.CurrentCulture; } 
 } 
 
 public static CultureInfo CurrentUICulture 
 { 
 get { return Thread.CurrentThread.CurrentUICulture; } 
 } 
 
 public static string CurrentDirectory 
 { 
 get { return AppDomain.CurrentDomain.BaseDirectory; } 
 } 
 
 public static string GetFilePath(string fileName) 
 { 
 return CurrentDirectory + @"\" + fileName; 
 } 

The list could go on, containing whatever centralized objects, properties, or methods that are needed.

Builder

Suppose you had a series of objects that needed constructed, but your application needs to specialize how they are built. This is where the builder pattern comes into play.  It handles performing the building of the necessary objects (also referred as the "product"); the builder class has that sole responsibility. The builder class also supports inheritance, which the product that the builder creates is usually involved in the inheritance scheme, meaning that the derived builder objects are actually building their related product object.

The builder pattern has a director that oversees the build process. The director has a reference to the builder(s) available and is responsible for invoking the correct method(s) in the builder. The builder has a common interface that all builders derive from and that the director knows about, and because of this, it can easily do its job.  Inheritance plays a key, as the builder's interface is abstract, and the derived builder classes actually do the work of building an object. The resulting class that it builds can make use of inheritance to provide a more specific implementation.  The builder class would be responsible for invoking the correct object.

It is possible that the builder/director relationship be dynamically created through the use of a configuration file, though that adds a lot of work to the software development process.  More simplistically and realistically, this relationship is statically created through a constructor or an initialization method.

Listing 14

public class SecurityZone 
 { 
 private IAuthorizationManager _manager = nullprivate IIdentity _user = nullpublic SecurityZone(string userID, IAuthorizationManager manager) 
 { 
 _manager = manager; 
 } 
 
 private void GetUserInstance() 
 { 
 if (_user != nullreturnif (_manager == nullthrow new ArgumentNullException("_manager"); 
 
 _user = _manager.GetuserInstance(); 
 } 
 
 public bool IsInRole(string roleName) 
 { 
 this.GetUserInstance(); 
 
 return Roles.IsUserInRole(_user.Name, roleName); 
 } 
 } 

In this case, the end product is the User, which is build from a class that implements the IAuthorizationManager interface.  The director is the SecurityZone class that oversees the authorization process.

Dependency Injection/Inversion of Control

The dependency injection pattern is a complicated pattern, one that I do not fully understand yet.  I first came across the pattern at http://www.martinfowler.com/articles/injection.html, and since then I am starting to get a glimpse of how it can work. It works through reflection and attributes.  Let me explain further.

Inversion of Control (IOC) works by getting a reference to a particular object dynamically.  It identifies the object through the use of attributes. An attribute is defined for a constructor, a property, or even the individual parameter of a constructor or method, that marks that object as needing a dynamic reference. The parent object, which uses reflection to inspect the metadata for the class, finds the attributes, gets a reference of the specific object type, and passes it in to the member.

Let us break this down some. There has to be some governing object that knows how to get a reference to a specific object marked through an attribute. The dynamic reference could be a derivative of the member's type that has the attribute. You will see this in the Composite UI Application Block (CAB); a module uses a work item, not the base class (WorkItem) but the derived class that the custom module defines. The module is linked to the derived work item through a code declaration, and the instance of the derived work item class is dynamically created through the Activator statements shown above.

I could also see how a specific instance of an object would be desired as well, which would require some sort of notation in the attribute to define this. For instance, you may have a requirement to get a reference to a user object that represents "John Doe" and not just any user object reference. The attribute would need some way to denote this, and since attributes are not generated dynamically, it may not be possible; unless the application uses code to create a link between the governing object and an injected object, say through the configuration file or an XML file or some sort.

Using Dependency Injection, a class could have the following notation for a property that marks it as needing a new instance of an object that matches the property type.

Listing 15

private UserInfo _user;
[CreateNew]
public UserInfo UserInformation
 {
  get 
  { 
    return _user; 
  }
   set 
  { 
    _user = value; 
  }
}

For this to work, there needs to be a governing object at a level above the UserInformation class that can parse the property, find the CreateNew attribute and create a UserInfo object, passing it to the property's setter.  As another example, injection could occur for a method declaration.

Listing 16

[Injection]
 public UserDetails[] GetUserDetails([ServiceDependency]UserInfo user)
{
  //DO something
}

The Injection attribute marks a method requiring the need for injection and the ServiceDependency attribute needs an injection of the UserInfo object into it. The application also needs to be able to get a reference to the UserInfo object that is part of the dependency (maybe defined in another object) and pass it into the method call.

This is an extent of what some of the IOC frameworks can do.  There are several IOC frameworks freely available.

·         Composite UI Application Block

·         Spring .NET

·         StructureMap

·         Castle

References

Conclusion

I hope that you have learned something about design patterns and object instantiation as a whole. These lists are definitely not complete, but are simply some important design considerations when developing software, and are some of the approaches to creating objects.  In addition, you can find plenty of information on the internet by just googling for one of the design pattern names.

Is it worth using design patterns? As a whole yes, but which pattern to choose can be a daunting task.  It is important to remember not to lose hope when you choose a pattern and later find that it would have been easier to choose an alternative pattern. While very helpful, design patterns are hard to apply because you need a grander scale of the design/requirements than is necessarily available to you at the time, which is why the principle of refactoring is very important.

Application development can be subjective for certain applications, meaning that there can be many solutions to one problem and they can all be the right approach.  What is important is not whether you have chosen the correct one, but whether you have implemented it well in your applications.



User Comments

No comments posted yet.






Community Advice: ASP | SQL | XML | Regular Expressions | Windows


©Copyright 1998-2024 ASPAlliance.com  |  Page Processed at 2024-03-29 1:48:59 AM  AspAlliance Recent Articles RSS Feed
About ASPAlliance | Newsgroups | Advertise | Authors | Email Lists | Feedback | Link To Us | Privacy | Search