Increased runtime flexibility and future proofing; the GOF
Creational Patterns with C#
BarryMossman<is_at>primos.com.au
(Note: I reworked this article on the 3rd of August 2004 to remove use of Interface declarations as I have found
them to be bad practice in most situations.)
The GOF design patterns help address the following challenges :
- design ready to accommodate change & growth
- design flexible systems that come ready to handle
reconfiguration and run time tailoring
- code in manner to facilitate reuse during the development and
extension phases ... ie. both external and internal reuse, so that
we are rewarded by efficiencies as the project progresses, coming
for investments made earlier in the project.
- implement change in a way that doesn't overly shorten the
system's useful lifespan
In a multi-person project the design patterns have the additional
utility of providing a shorthand language with which to describe
design options and specifications.
This article is the first in a series, and discusses why and when
you would want to use the design patterns, and demonstrates a C#
implementation of the patterns. There is source code for my
demonstration program available from CodeCentral
under ID
21604. The program contains annotated example displays, and also
displays some notes about the patterns, so if you are interested in
starting to work with the patterns it may be a useful utility to have
on your desktop during the learning period.
The design patterns were defined in the programming classic
entitled "Design Patterns" by Gamma, Helm, Johnson &
Vlissides. The four authors are commonly described as the Gang Of
Four (GOF) for brevity. The subtitle of the book is "elements
of reusable object-oriented software". If you are not familiar
with the book you have probably seen it in a bookshop somewhere.
The GOF described various categories of patterns:
- Creational Patterns <=== discussed in this article
-
Structural Patterns
- Behavioral Patterns
The Creational Patterns are:
General techniques promoted by the GOF
Decouple our client code from the
classes of the objects that it uses:
Why ?
- Code our client so that it uses like classes generically, to
reduce the need for switch blocks.
-
Anticipate the virtually certainty that it will become necessary, in
the future, to change the implementation of the classes that our
client uses.
- When this happens maybe:
- we need to leave the old version 1 class in place as other
clients are still using it (the need to ensure absolute backwards
compatibility is a task that is nice to avoid)
- our new enhanced system is going to be more flexible, and the
actual class which is to be instantiated by our client can now vary
at runtime. Perhaps we now have have several subclasses inheriting
from the version 1 class, and runtime conditions will determine
which of the subclasses that we will need to instantiate.
- our new release introduces some form of object pooling so that
the client is no longer causing the creation of new object for each
individual use.
- The aim is to write our client in such a manner that these kind
of change can occur to the objects that it uses, without forcing
code changes within the client itself.
- The general technique is to outsource object creation to one
of these Creational Design Patterns, and then to reference the
objects created via a base class rather than addressing them
explicitly via their concrete class types.
Favour "object composition"
over "class inheritance"
- in "class inheritance":
- the issue of code reuse is addressed by breaking our business
objects down to generic classes where possible, and then build up
to the classes we actually use via class inheritance.
- has the advantages that this supported by the programming
language, is simple to use, and the resulting application
architecture is easy to understand
- has the disadvantages that
- can lead to an implementation where the parent classes have
too much bearing on the subclass's implementation. Encapsulation
becomes compromised as the subclasses can have too much knowledge
of their parent's implementation. Change at either level is liable
to require change at the other level. Reuse of a subclass for a
future extension is more likely to require change at the parent
level also.
- hampers runtime flexibility where we would able to change the
behaviours being inherited, as this has been decided at compile
time.
- reuse is only available at the whole logical object level,
rather than at the level of just one of the behaviours of the
logical object
- "object composition"
- here the business objects that our client will use are
assembled from a number of helper classes working together to
assemble the behaviour required that would have been delivered by
the class inheritance model used in the class inheritance
technique.
- has the advantages that:
- our objects can be more flexible because their behaviour can
be assembled dynamically at runtime, rather than fixed at compile
time through inheritance
- we are less likely to allow our classes grow into unmanageable
size
- we are likely to get good levels of reuse, and reduced levels
of rework.
- but has the disadvantage that our system design can be harder
to understand as it's operation is delivered via the
inter-relationships between the helper classes rather than from
just a few business classes
- the Design Patterns themselves provide a language with which
we can describe and document the system design to help overcome
this disadvantage
- Note that the advice is to only to "favour"
object composition over class inheritance, not to stop using
inheritance altogether. The two techniques work well together
Algorithms that are likely to change
should be isolated into a to reduce the impact when this happens.
The Creational Patterns have an important part to play in the
deployment of these techniques that the GOF are advocating
- the Creational Patterns provide the structures to achieve the
object of decoupling our client from the classes that it uses
- the Creation Patterns are not involved in the object
composition approach to system design, but this approach will
result in your application having an increased quantity of physical
classes. The success of the strategy when faced with future growth
or change, depends upon decoupling, which makes the Creational
Patterns crucial.
- The logic involved in the instantiation and initialisation
of the classes that we deploy will be a likely area for future
change. This makes these algorithms likely candidates for
isolation, and the Creational Patterns are those which achieve this
objective.
A summary of the patterns
|
Pattern Name |
General objective |
|
Factory |
Most basic creational pattern.
Can be used on it's own, or used within the
patterns following.
Delivers all the basic objectives mentioned above.
|
|
Abstract Factory |
Allows us to group the objects that we want to use
into families.
Our client can then decide which family it wants to
use based upon some configuration or runtime option.
The Abstract Factory will instantiate objects from
just the chosen family.
Our client will operate with objects from the
chosen family using generic calls that would work with any other
family. |
|
Prototype |
We first build and configure a prototype, maybe
using one of the other patterns.
Our client can then clone from the prototype to
create instances as it requires them.
Our client can operate, with generic code, upon
either the prototype, or upon any of the clones.
Facilitates runtime flexibility as we can control
how the prototype is configured at runtime, and then our client
can create cloned instances as required as if this was a class
that was defined into the system at compile time. |
|
Builder |
The building of our object is outsourced to two
helper classes.
One class controls what is built, and the other
controls how it is built.
This means that we can have features and options
with the classes that we use, as well as decoupling our client
from the physical classes that it is uses.
The mechanics of the features and options assembly
is outsourced from our client. |
|
Singleton |
This is a specialist pattern that gives the client
access to an object that is created with only the one instance,
and is shared across the application.
The pattern relieves the client of the
responsibility of ensuring that there is just the one instance
regardless of how many attempts are made to instantiate the
object. |
Factory Pattern
To illustrate the benefits of the Factory pattern my demonstration
client program uses an object that provides a public method called
SayWho, which returns a string showing
the object's name. Here is an example of it's use:
listBox1.AppendText(Product.SayWho());
The aim is to have the client instantiate and use this object in a manner that is accepting of change.
IT will become the "product" of our factory. If there are various flavours of product we want to write reuable
generic code rather than have untidy switch blocks all through our
code. We want to be able to provide a new implementation of the
functionality that was provided by the initial "product"
class, but have the same client still able to run without change,
now using the new product class.
To achieve this first we define a base class for our "product" objects.
// --- Abstract product
abstract public class ProductBase {
public string SayWho() {
return "n * " + this.ToString();
}
}
We then create a factory class to instantiate "product"
objects. This is done so that the instantiation of the "product"
class is outsourced away from our client, meaning that our client no
longer need know the class name of the object that is using. I have
passed a parameter into the factory's MakeProduct method so that the
factory could be later changed to be more flexible about the flavour
of product that it instantiates.
// --- Abstract factory
public abstract class FactoryBase {
abstract public ProductBase MakeProduct(int t);
}
// --- Concrete factories
public class ConcreteFactory_A: FactoryBase {
public override ProductBase MakeProduct(int t) {
return new ConcreteProduct_A();
}
}
We can now code our client as follows. Note that the "product"
variable is defined using the base class. rather than the concrete
class that will be instantiated. We will be able to change the class
of product that this client uses by issuing a new version of the
ConcreteFactory class that returns a different class of product.
As long as the new product implements the same signature as the old
product our client will not notice the difference.
FactoryBase Fact = new ConcreteFactory_A();
ProductBase Product = Fact.MakeProduct(0);
listBox1.AppendText(Product.SayWho());
To get a little leverage out of the factory pattern we need to need
to define a second similar product. We will create a B factory that
makes B-type objects. This factory can make two types of object, one
extends interface to now also show provide a SayWhen behaviour. Firstly
we should look at the concrete implementation of the products.
// --- Concrete products
public class ConcreteProduct_A: ProductBase {}
public class ConcreteProduct_B_1: ProductBase {}
public class ConcreteProduct_B_2: ProductBase {
public string SayWhen() {
return (String.Format("n *
{0:f}",System.DateTime.Now));
}
}
Then the new factory.
public class ConcreteFactory_B: FactoryBase {
override public ProductBase MakeProduct(int t) {
switch (t) {
case 1:
return new ConcreteProduct_B_1();
case 2:
return new ConcreteProduct_B_2();
default:
throw new Exception("Invalid product
request");
}
}
}
The client can use the new products with an unchanged
"Product.SayWho()" call. It can also be coded to
recognise the products with the extended behaviour, and use this
behaviour when appropriate.
Fact = new ConcreteFactory_B();
Product = Fact.MakeProduct(1);
listBox1.AppendText(Product.SayWho());
if (Product is ConcreteProduct_B_2)
listBox1.AppendText(((ConcreteProduct_B_2)Product).SayWhen());}
If version 2 of our application requires modification to a "product"
class we can produce a new factory to produce the new version
objects. Another approach is to descend from the version 1 factory,
and handle any new version products from the descendant, but let the
version 1 factory continue to produce an heritage products.
public class ConcreteFactory_B_V2: ConcreteFactory_B {
override public ProductBase MakeProduct(int t) {
switch (t) {
case 3:
return new ConcreteProduct_B_1_V2();
default:
return base.MakeProduct(t);
}
}
}
Abstract
Factory Pattern
The Factory pattern allowed us to decouple our client from an
object which it uses. The Abstract Factory pattern extends this idea
to allow us to decouple from separate families of objects.
A runtime selection, or configuration option, in our client could
decide which family of objects is to be used. The Abstract Factory
pattern allows us to write generic code to instantiate and use the
family objects regardless of which family is chosen at runtime. The
pattern also helps us enforce that objects from just the chosen
family are used uniformly by the client.
The classes in my demonstration program's "family"
each provide the public SayWho, and sometimes the SayWhen methods as
in the Factory pattern example. This similarity of function is just
to simplify the example. The "product" classes within the family do not need to
bear any similarity, it just that each family should a similar
structure, ie. same number of classes, and when looking across
the families, each equivalent class should have the same public
signature.
/* -----------------------------
The products within a single family do not need to descent from a common
ancestor but we need to ensure that across families the various products
have the same interface.
FamilyA Familyb
------- -------
Product1 Product1 <-- These should have a common interface.
Product2 Product2 <-- These may be different to those above,
but they need to be the same as each
other.
Product3 Product3 <-- etc
------------------------------------------ */
The Product classes that need the same interface may not descent from
a common base class. I will connect them together via interface
definitions so that the client can recognise them, and so that the
compiler will ensure that I have implemented them uniformly.
Use of the Abstract Factory pattern means that generic code such
as the following client code can be used upon an object family.
private void AbstractFactory_CreateAndUseFamilyProducts(FactoryBase
AF) {
/* Either family A or family B products are created dependant upon
the concrete factory that was passed in via the AF paramter*/
IProduct1 AP1 = AF.CreateProduct1();
IProduct2 AP2 = AF.CreateProduct2();
IProduct3 AP3 = AF.CreateProduct3();
// use family members generically
AbstractFactory_UseProductsGenerically(AP1);
AbstractFactory_UseProductsGenerically(AP2);
// or use a specific family member
listBox1.AppendText(AP3.SayWho());
}
private void AbstractFactory_UseProductsGenerically(IProductBase AP) {
listBox1.AppendText(AP.SayWho());
if (AP is IProduct2)
listBox1.AppendText(((IProduct2)AP).SayWhen());
}
The client can use products from either family without change.
FactoryBase AF = new ConcreteFactory_A();
// Use family A products
ShowUserCommentary(1); // display explanatory notes on the UI
AbstractFactory_CreateAndUseFamilyProducts(AF);
// or have the same code create and use family B products
ShowUserCommentary(2);
AF = new ConcreteFactory_B();
AbstractFactory_CreateAndUseFamilyProducts(AF);
The above causes my demonstration program to display:

To implement the Abstract Factory we firstly define interfaces for
our family set:
public interface IProductBase { //
optional
string SayWho();
}
public interface IProduct1: IProductBase {}
public interface IProduct2: IProductBase {
string SayWhen();
}
Then our concrete products:
// --- Concrete products
public class ConcreteProduct_A_1: ProductBase, IProduct1 {
}
public class ConcreteProduct_A_2: ProductBase, IProduct2 {
public string SayWhen() {
return (String.Format("n *
{0:f}",System.DateTime.Now));
}
}
public class ConcreteProduct_A_3: ProductBase, IProduct3 {}
public class ConcreteProduct_B_1: ProductBase, IProduct1 {}
public class ConcreteProduct_B_2: ProductBase, IProduct2 {
public string SayWhen() {
return (String.Format("n *
{0:f}",System.DateTime.Now));
}
}
public class ConcreteProduct_B_3: ProductBase, IProduct3 {}
We then define the base class for our Abstract Factories:
// --- Abstract Factory
abstract public class FactoryBase {
abstract public IProduct1 CreateProduct1();
abstract public IProduct2 CreateProduct2();
abstract public IProduct3 CreateProduct3();
}
Finally the concrete classes for the abstract factories:
// --- Concrete factories
public class ConcreteFactory_A: FactoryBase {
public override IProduct1 CreateProduct1() {
return new ConcreteProduct_A_1();
}
public override IProduct2 CreateProduct2() {
return new ConcreteProduct_A_2();
}
public override IProduct3 CreateProduct3() {
return new ConcreteProduct_A_3();
}
}
public class ConcreteFactory_B: FactoryBase {
public override IProduct1 CreateProduct1() {
return new ConcreteProduct_B_1();
}
public override IProduct2 CreateProduct2() {
return new ConcreteProduct_B_2();
}
public override IProduct3 CreateProduct3() {
return new ConcreteProduct_B_3();
}
}
Prototype
Pattern
The Prototype Pattern approaches the creation of the objects that
our client will use by cloning instances as required from prototypes.
This achieves the general aim of decoupling the client from the
objects that it will use, but also adds some advantages unique to the
Prototype pattern.
The example program uses the one class to build prototypes from.
This class has the SayWhen behaviour from the other examples. The
prototypes are set up to show the datetime in differing formats.
Clones are then created. The clones are altered by having the time
print in lower case, so that we can see that each clone is a separate
instance from the prototype from which it was made.
Here is the client code that creates and uses the above instances of
prototypes and clones. This could be further improved by using the
Factory Pattern to create the prototypes, in this way the client code
will not be aware of the class being used. I have not done this so
that we can focus upon just the Prototype pattern.
/* In this example a method in the generic object states
it's type and
gives the date. The various "sub-types" use differing time formats.
The property ynShout controls whether the time is converted to
uppercase. The intent is to show that we can use the prototype pattern
to create differing flavours of our class by varying the prototype. */
// create a product; state time using DateTime format "y"
ProductBase pr = new ConcreteProduct("y");
// now use Prototype pattern capability to clone a copy
ProductBase clone = pr.Clone();
// change original so can be seen to be seperate instance from the clone
pr.Shout = true;
// create, and clone, a different flavour product; format "f"
ProductBase pr2 = new ConcreteProduct("f");
ProductBase clone2 = pr2.Clone();
pr2.Shout = true;
// use either the original, or the clone, using generic code
ShowUserCommentary(1);
UseProduct(pr);
ShowUserCommentary(2);
UseProduct(clone);
ShowUserCommentary(3);
UseProduct(pr2);
UseProduct(clone2);
}
private void UseProduct(ProductBase product) {
listBox1.AppendText(product.SayWhen());
}
Here is the implementation of the class that our client is using to
build the prototypes from. Focus upon the Clone method, as the other
code just relates to my demonstration example rather that the
Prototype pattern itself. Note that the .NET framework makes it easy
for us to implement a basic form of cloning via the Memberwise Clone
method.
// --- Abstract Product
public abstract class ProductBase {
// fields
protected string _whenFormat;
private Boolean _shout = false;
// properties
public string WhenFormat {
get {
return _whenFormat;
}
set {
_whenFormat = "{0:" + value + "}";
}
}
public Boolean Shout {
get {
return _shout;
}
set {
_shout = value;
}
}
// constructors
public ProductBase( string ID ) {
WhenFormat = ID;
}
// methods
public abstract string SayWhen();
public ProductBase Clone() {
// Shallow copy
return (ProductBase)this.MemberwiseClone();
}
}
// --- Concrete products
public class ConcreteProduct: ProductBase {
// constructors
public ConcreteProduct(string ID) : base (ID) {}
// methods
override public string SayWhen() {
string _st1 = "n * " + this.ToString()+ ": ";
string _st2 = String.Format(this._whenFormat,System.DateTime.Now);
string _st2a = this.Shout ? _st2.ToUpper() : _st2;
return(_st1 + _st2a);
}
}
I said above that the MemberwiseClone method
provides a basic version of cloning. This is because
MemberwiseClone provides just a shallow copy of the prototype.
This means that if our prototype contained references to associated
or child objects, the clone created will share the same associates or
children that the prototype used. If we were wanting to clone a whole
new structure our clone method would need to call MemberwiseClone for
each of the object that the prototype refers to.
Builder Pattern
The Builder pattern becomes useful where our client uses objects
that are more complex to construct than just a simple "= new
YourClass()". This pattern uses two entities which collaborate
to build the target class;
This creational pattern facilitates a system design where the
objects that we use could be considered to have features and options
that are dynamically chosen at run time.
Also the "object" built by the Builder could be more
complex than just the instantiation of just a single class. The
builder could for example built an instance of the main object, then
build several associated or child objects that the main object will
contain references to. Our client will be shielded from this
complexity. From it's perspective it is just asks for, and gets
returned, a simple object instance.
In my example the object my client is to use has the now familiar
SayWho method.
I have two Builders:
one creates an object whose SayWho behaviour is to issue a
greeting and state the class name of it's builder
the other object does as above, then also states it's
creation time
I have two Directors:
The client therefore has the flexibility of being able to build
either object, and then to have the object built in the chosen style.
It does that by choosing which Builder & Director to use to
create the object. The client is shielded from which actual class is
built and how it is constructed, as it's generic use of the object
will work with whichever class is actually built.
Here is the output from my demonstration program.
Here is the client code that produces the above output.
The client is shielded from knowing which class of object is
actually created, and is also shielded from knowing how the object is
configured.
// Create a Builder & a Director
director = new DirectorTerse();
builder = new BuildUntimedGreeting();
// Now use these to create an object, and then use that object.
BuildAndUseObject(director, builder);
ShowUserCommentary(2);
// Create another Director. Use it with the previous Builder, using
// the same generic client code, to create the same type of object
// but with different behaviour due to different creation options
// taken by the new Director.
director = new DirectorChatty();
BuildAndUseObject(director, builder);
ShowUserCommentary(3);
// Create a new Builder which builds a new generation object.
// Create the object using the 1st Director. So we have the same
// creational/setup instructions from the Director & the same client
// code, but we get different behaviour when using the object with
// the same generic client code.
builder = new BuildTimedGreeting();
director = new DirectorTerse();
BuildAndUseObject(director, builder);
ShowUserCommentary(4);
// Same story with the new Builder with the second Director.
director = new DirectorChatty();
BuildAndUseObject(director, builder);
}
/* Generic code to create and use the object */
private void BuildAndUseObject(DirectorBase director, BuilderBase builder) {
ProductBase product;
director.Construct(builder);
product = builder.GetResult();
listBox1.AppendText(product.SayWho());
}
Firstly we will look at the Builders which determine which object is
to be built and returned to the client. The configuration of the
object to be built (in my case the _message, _owner &
_timestampFormat variables) will be set up by the Director). The only
section that is relates to the Builder pattern is the GetResult
method which returns the constructed object to the client. The
remainder are just part of the functionality of my demonstration
program.
// --- Abstract Builder
abstract public class BuilderBase {
// fields
protected string _message;
protected string _owner;
// methods
public void BuildMessage(string text) {
_message = text;
}
public void BuildOwner(string owner) {
_owner = owner;
}
virtual public void BuildTimeStampFormat(string timestampFormat) {}
abstract public ProductBase GetResult();
}
// --- Concrete Builders
public class BuildUntimedGreeting: BuilderBase {
override public ProductBase GetResult() {
return new UntimedGreeting(_message,_owner);
}
}
public class BuildTimedGreeting: BuilderBase {
// fields
private string _timestampFormat;
// methods
override public ProductBase GetResult() {
return new TimedGreeting(_message,_owner,_timestampFormat);
}
override public void BuildTimeStampFormat(string timestampFormat) {
_timestampFormat = timestampFormat;
}
}
Then we have the Directors which control how the Builder constructs
the object to be built.
// --- Abstract Director
public abstract class DirectorBase {
abstract public void Construct(BuilderBase builder);
}
// --- Concrete Directors
public class DirectorTerse: DirectorBase {
// methods
override public void Construct(BuilderBase builder) {
builder.BuildMessage("Hi");
builder.BuildOwner(this.ToString());
builder.BuildTimeStampFormat("t");
}
}
public class DirectorChatty: DirectorBase {
// methods
override public void Construct(BuilderBase builder) {
builder.BuildMessage("Hello it is wonderful to see you.");
builder.BuildOwner(this.ToString());
builder.BuildTimeStampFormat("F");
}
}
Finally for completion here is the implementation of one of the
objects that will be created by my demonstration of the Builder
pattern.
// --- Abstract Product
abstract public class ProductBase {
abstract public string SayWho();
}
// --- Concrete products
public class UntimedGreeting: ProductBase {
// fields
private string _text;
private string _owner;
// constructer
public UntimedGreeting(string input, string owner) {
_text = input;
_owner = owner;
}
// methods
override public string SayWho() {
return String.Format(" * {0}n * I was build by
{1}n",
_text,_owner);
}
}
Singleton
Pattern
The Singleton pattern is a specialist creational pattern as it's
primary focus is to facilitate a single shared instance of our object
rather than to decouple our client from the object's implementation
as with the other creational patterns.
The pattern is useful when our design requires an object for which
there must be only one instance that will be shared across the
application. The point of the pattern is relieve the client of the
task of ensuring that there is only once instance of this object.
This will simplify the client by allowing it to focus upon the
business intent rather than a mechanics issue such as the singleton
requirement. It will also avoid a potential client program bug where
one reference to the object incorrectly allows another instance to be
created. The following shows the client "creating" and
using the singleton object.
ShowUserCommentary(1);
// call for a singleton instance. Since this is the first call this
//will trigger the creation of the instance.
SingletonObject product1 = SingletonObject.Instance;
// use the instance
listBox1.AppendText(product1.SayWho());
ShowUserCommentary(2);
// call for a singleton instance again. We will get given the same
// instance
SingletonObject product2 = SingletonObject.Instance;
listBox1.AppendText(product2.SayWho());
This produces the following output from my demonstration program
which shows the same singleton instance has been attached to both
IProduct variables..
C# and the .NET framework make it easy for us to implement the
Singleton pattern. Here is an implementation based upon ideas in an
MSDN article I saw by Mark Townsend of Microsoft (see link at the end
of this article). The instantiation of the SingletonObject class is
triggered by the first reference to it's static Instance property.
Since the SingletonObject 's class's constructor is not static, the
static Instance property is initialised after the
initialisation of the class which allows us to have the property
return an instance of the class that contains it.
// concrete Singleton
public class SingletonObject {
// fields
private static readonly SingletonObject singletonObjectInstance = new
SingletonObject();
long _countUse = 1;
// properties
public static SingletonObject Instance {
get {
return singletonObjectInstance;
}
}
// constructor
private SingletonObject() {} // private, so cannot be used by a
client
// methods
public string SayWho() {
return String.Format(" * {0}: used {1}
timesn",this.ToString(),_countUse++);
}
}
Conclusion
This article has examined just the Creational Patterns from those
described by the GOF in their book titled "Design patterns".
I think that the study of their design patterns is a worthwhile thing
to do. I found the following links helpful while studying the
patterns myself and while preparing this article. The book itself is
a good investment as it provides supplementary detail upon the
problems that the patterns are trying to solve, the elements of the
solution, and the consequences and trade-offs involved in using the
patterns.
In my next article I look at the Structural
Patterns.
Links
Connect with Us