Design Patterns
Article 2
Author: Douglas Minnaar
Level: Novice – Intermediate
Prerequisites:
- Understanding of Object Oriented Programming
- The examples will be demonstrated in C#.NET therefore an understanding of C#.NET code is required
Download code here
Summary
It is not the intent of the Design Pattern Series to focus on providing a theoretical knowledge dump of all there is to know about design patterns. There are many books that do that already. Instead, this series will focus on providing lots of practical examples. However, there will be some theory to help address important points concerning design patterns. I use the theory of design patterns mostly as a guide and instead make references to good design pattern books for more detail explanation. Think of this series as a ‘Design Patterns by example’ series. The target audience is that of a novice to intermediate software developer.
Part 2 – GOF Design Patterns
In part 2 we look at another creational design pattern namely the Abstract Factory. In terms of the Factory Method and Abstract Factory, the whole idea is to isolate client code from changes. In other words, one would like to be able to make changes to the way an object is created without affecting the client code in terms of changes having to be made.
Abstract Factory
Please refer to the GOF book or any other good design pattern book for more detailed information pertaining to the Abstract Factory.
The intent of the Abstract Factory is to provide an interface for creating families of related or dependent objects without specifying their concrete classes.
One should consider using an Abstract Factory when
- a system must be decoupled from how its products are created. In other words, a system must be able to create products without specifying concrete product classes. Therefore, one is able to isolate ones concrete classes from the client
- a system must be configured with one of a set of products
- a constraint must be enforced so that a group of products are designed to be used together
- one wishes to expose a library of classes as a set of interfaces. Therefore, a client can only change a product through it's interface
- one wishes to change the configuration of how products are created without changing client code
A caveat of the Abstract Factory is that when one wishes to add another product family, one is required to change the Abastract Factory interface. This has the affect that one is required to change the interface of the Abstract Factory subclasses. There are ways around this problem. One may choose to implement an Abstract Factory that exposes a single Factory Method that can be used to create various products based on certain input criteria. The Factory Method would then have the responsibility in terms of deciding what product to create. Therefore, the creation of products is not left to the Abstract Factory subclasses to determine what product to create, but is left to a single Factory Method instead.
Structure
The following diagrams illustrate the basic Abstract Factory structure.
In this diagram, the Abstract Factory determines what products to create. I then have another Factory (Client) that is used to create an Abstract Factory using a Factory Method (CreateProductFactory())


namespace CodeMentor.Patterns.GOF.Creational.AbstractFactory.Structure
{
public abstract class BaseProductFactory
{
protected BaseProductFactory()
{
}
public abstract BaseProductA ProductA { get; }
public abstract BaseProductB ProductB { get; }
}
}
namespace CodeMentor.Patterns.GOF.Creational.AbstractFactory.Structure
{
public class ProductFactory1 : BaseProductFactory
{
public ProductFactory1()
{
}
public override BaseProductA ProductA
{
get { return new ProductA1(); }
}
public override BaseProductB ProductB
{
get { return new ProductB1(); }
}
}
}
namespace CodeMentor.Patterns.GOF.Creational.AbstractFactory.Structure
{
public class ProductFactory2 : BaseProductFactory
{
public ProductFactory2()
: base()
{
}
public override BaseProductA ProductA
{
get { return new ProductA2(); }
}
public override BaseProductB ProductB
{
get { return new ProductB2(); }
}
}
}

namespace CodeMentor.Patterns.GOF.Creational.AbstractFactory.Structure
{
public abstract class BaseProductA
{
protected BaseProductA()
{
}
public abstract string Description { get; }
}
}
namespace CodeMentor.Patterns.GOF.Creational.AbstractFactory.Structure
{
public class ProductA1 : BaseProductA
{
public ProductA1()
: base()
{
}
public override string Description
{
get { return "Product A1"; }
}
}
}
namespace CodeMentor.Patterns.GOF.Creational.AbstractFactory.Structure
{
public class ProductA2 : BaseProductA
{
public ProductA2()
: base()
{
}
public override string Description
{
get { return "Product A2"; }
}
}
}

namespace CodeMentor.Patterns.GOF.Creational.AbstractFactory.Structure
{
public abstract class BaseProductB
{
protected BaseProductB()
{
}
public abstract string Name { get; }
}
}
namespace CodeMentor.Patterns.GOF.Creational.AbstractFactory.Structure
{
public class ProductB1 : BaseProductB
{
public ProductB1()
: base()
{
}
public override string Name
{
get { return "ProductB1"; }
}
}
}
namespace CodeMentor.Patterns.GOF.Creational.AbstractFactory.Structure
{
public class ProductB2 : BaseProductB
{
public ProductB2()
: base()
{
}
public override string Name
{
get { return "ProductB2"; }
}
}
}

namespace CodeMentor.Patterns.GOF.Creational.AbstractFactory.Structure
{
public static class Client
{
public static BaseProductFactory CreateProductFactory(string factory)
{
switch (factory.ToUpper().Trim())
{
case("PRODUCTFACTORY1"):
return new ProductFactory1();
case("PRODUCTFACTORY2"):
return new ProductFactory2();
default:
return null;
}
}
}
}
The test code for the Abstract Factory Structure is as follows:
public static void TestProductFactory1()
{
Console.WriteLine("-- Testing Product Factory 1 --");
Console.WriteLine();
BaseProductFactory factory = Client.CreateProductFactory("PRODUCTFACTORY1");
BaseProductA productA = factory.ProductA;
Console.WriteLine("Product A Description for Product Factory 1 : {0}", productA.Description);
BaseProductB productB = factory.ProductB;
Console.WriteLine("Product B Name for Product Factory 1 : {0}", productB.Name);
}
public static void TestProductFactory2()
{
Console.WriteLine("-- Testing Product Factory 2 --");
Console.WriteLine();
BaseProductFactory factory = Client.CreateProductFactory("PRODUCTFACTORY2");
BaseProductA productA = factory.ProductA;
Console.WriteLine("Product A Description for Product Factory 2 : {0}", productA.Description);
BaseProductB productB = factory.ProductB;
Console.WriteLine("Product B Name for Product Factory 2 : {0}", productB.Name);
}
The result of the Structure test is as follows:
Examples
Please note that the names I use to represent certain entities in the examples are intended to be fictitious.
Example 1 : Bank
We will build on the knowledge acquired from the Banking example for the Factory Method from the previous article. Lets pretend that we are required to create a simple ATM (Automatic Teller Machine) that allows one to not only perform banking operations, but also other services that may be made available from Third Party vendors. Typically, one would withdraw money, query balances, do transfers, etc at an ATM. What if we could make it possible to extend our application in such a way that one could 'plug-in' additional services without having to redesign our application. A third party service may be something like being able to pay your speeding fines (something that I use quiet often at our local ATM machines), or being able to purchase air time for a pre-paid cellular phone account. However, we want a client to be able to access these services regardless of the clients banking provider. Therefore, whether a client has a Bank_ABC ATM card or a Bank_XYZ ATM card, the ATM application will provide a common interface into using a family of services without specifying the specifics of that service. Therefore, our interface must be an abstraction of the services that are available. By allowing for this mechanism, one can add additional Banking vendor services or third party services without having to redesign the ATM application. The reason for this is because we are essentially striving for a design whereby we decouple the interface from how the services (products) will be created. Because we do not have an ATM machine or an ATM card, we will only use a PIN (Personal Identification Number) to uniquely identify a client. This will in turn allow the BankProviderService to retrieve the appropriate services.
The following diagram represents an overview of our very simple ATM application.

We will provide the following services (products) for our BankProviderService (Factory).
- BankAccountProvider - Provide client with the relevant BankAccountProvider service that will allow a client to view and manage bank account details.
using System;
using System.Collections.Generic;
namespace CodeMentor.Patterns.GOF.Creational.AbstractFactory.Examples.Banking
{
public abstract class BaseAccountProvider
{
protected BaseAccountProvider(BaseAuthorizationToken auhtorizationToken)
{
AuthorizationToken = authorizationToken;
}
/// <summary>
/// Retrieve Account details based on the provided account number
/// as well as the authorization token associated with this instance
/// </summary>
/// <param name="accountNumber">Account Number</param>
/// <returns>Account</returns>
public abstract BaseAccount GetAccount(string accountNumber);
/// <summary>
/// Retrieve list of accounts based on the authorization token
/// assosiated with this instance
/// </summary>
public abstract List<BaseAccount> AccountList { get; }
private BaseAuthorizationToken authorizationToken;
/// <summary>
/// The Authorization token provides only the neccessary
/// information to indicate the authorization details required
/// to access account information
/// </summary>
public BaseAuthorizationToken AuthorizationToken
{
get { return authorizationToken; }
protected set { authorizationToken = value; }
}
}
}
using System.Collections.Generic;
namespace CodeMentor.Patterns.GOF.Creational.AbstractFactory.Examples.Banking
{
public class BankOfMarsAccountProvider : BaseAccountProvider
{
public BankOfMarsAccountProvider(BaseAuthorizationToken authorizationToken)
: base(authorizationToken)
{
}
public override BaseAccount GetAccount(string accountNumber)
{
// Logic to retrieve a valid Account based on provided
// account number
return new BankOfMarsAccount();
}
public override List<BaseAccount> AccountList
{
// Logic to retrieve a List of Accounts based on the
// Authorization Token associated with this instance
get { return new List<BaseAccount>(); }
}
}
}
using System.Collections.Generic;
namespace CodeMentor.Patterns.GOF.Creational.AbstractFactory.Examples.Banking
{
public class BankOfNeptuneAccountProvider : BaseAccountProvider
{
public BankOfNeptuneAccountProvider(BaseAuthorizationToken authorizationToken)
: base(authorizationToken)
{
}
public override BaseAccount GetAccount(string accountNumber)
{
// Logic to retrieve a valid Account based on provided
// account number
return new BankOfNeptuneAccount();
}
public override List<BaseAccount> AccountList
{
// Logic to retrieve a List of Accounts based on the
// Authorization Token associated with this instance
get { return new List<BaseAccount>(); }
}
}
}
- AuthorizationService - The AuthorizationService will merely authorize a client based on the provided PIN.
namespace CodeMentor.Patterns.GOF.Creational.AbstractFactory.Examples.Banking
{
/// <summary>
/// The BaseAuthorizationService is used to validate a user
/// in terms of performing banking and third party service
/// activities
/// </summary>
public abstract class BaseAuthorizationService
{
protected BaseAuthorizationService()
{
}
/// <summary>
/// Retrieve an Authorization Token based on a set of provided
/// security credentials. I use a string for simplicity and
/// demonstration purposes.
/// </summary>
/// <param name="requiredAuthorizationCredentials">Credentials</param>
/// <returns>Authorization Token</returns>
public abstract BaseAuthorizationToken GetAuthorizationToken(
IBankProviderServiceCredentials bankProviderServiceCredentials);
}
}
namespace CodeMentor.Patterns.GOF.Creational.AbstractFactory.Examples.Banking
{
public class BankOfNeptuneAuthorizationService : BaseAuthorizationService
{
public BankOfNeptuneAuthorizationService()
: base()
{
}
public override BaseAuthorizationToken GetAuthorizationToken(
IBankProviderServiceCredentials bankProviderServiceCredentials)
{
return new BankOfNeptuneAuthorizationToken();
}
}
}
namespace CodeMentor.Patterns.GOF.Creational.AbstractFactory.Examples.Banking
{
public class BankOfMarsAuthorizationService : BaseAuthorizationService
{
public BankOfMarsAuthorizationService()
: base()
{
}
public override BaseAuthorizationToken GetAuthorizationToken(
IBankProviderServiceCredentials bankProviderServiceCredentials)
{
return new BankOfMarsAuthorizationToken();
}
}
}
- ThirdPartyService - This is an abstract term to refer to any third party service that one would wish to add. The whole idea is that one can add many more services (whether they are third party or not). I only have one third party service (called ThirdPartyService) for demonstration purposes.
namespace CodeMentor.Patterns.GOF.Creational.AbstractFactory.Examples.Banking
{
public abstract class BaseThirdPartyService
{
protected BaseThirdPartyService()
{
}
/// <summary>
/// Method1 is simply a placeholder to indicate a method
/// that may form part of a third party service interface
/// </summary>
public abstract void Method1();
}
}
using System;
namespace CodeMentor.Patterns.GOF.Creational.AbstractFactory.Examples.Banking
{
public class BankOfMarsThirdPartyService : BaseThirdPartyService
{
public BankOfMarsThirdPartyService()
: base()
{
}
public override void Method1()
{
Console.WriteLine("Bank of Mars Third Party Service Method 1");
}
}
}
using System;
namespace CodeMentor.Patterns.GOF.Creational.AbstractFactory.Examples.Banking
{
public class BankOfNeptuneThirdPartyService : BaseThirdPartyService
{
public BankOfNeptuneThirdPartyService()
: base()
{
}
public override void Method1()
{
Console.WriteLine("Bank of Neptune Third Party Service Method 1");
}
}
}
We use the following Factories (Represent Banking Provider Services that will provide access to a number of other ATM application services)
- BankOfMarsProviderService
- BankOfNeptuneProviderService
namespace CodeMentor.Patterns.GOF.Creational.AbstractFactory.Examples.Banking
{
public abstract class BaseBankProviderService
{
protected BaseBankProviderService(
IBankProviderServiceCredentials bankProviderServiceCredentials)
{
BankProviderServiceCredentials = bankProviderServiceCredentials;
}
public abstract BaseAccountProvider AccountProvider { get; }
public abstract BaseAuthorizationService AuthorizationService { get; }
public abstract BaseThirdPartyService ThirdPartyService { get; }
private IBankProviderServiceCredentials bankProviderServiceCredentials;
public IBankProviderServiceCredentials BankProviderServiceCredentials
{
get { return bankProviderServiceCredentials; }
protected set { bankProviderServiceCredentials = value; }
}
}
}
namespace CodeMentor.Patterns.GOF.Creational.AbstractFactory.Examples.Banking
{
public class BankOfMarsBankProviderService : BaseBankProviderService
{
public BankOfMarsBankProviderService(
IBankProviderServiceCredentials bankProviderServiceCredentials)
: base(bankProviderServiceCredentials)
{
}
public override BaseAccountProvider AccountProvider
{
get
{
return new BankOfMarsAccountProvider(
AuthorizationService.GetAuthorizationToken(
BankProviderServiceCredentials));
}
}
public override BaseAuthorizationService AuthorizationService
{
get { return new BankOfMarsAuthorizationService(); }
}
public override BaseThirdPartyService ThirdPartyService
{
get { return new BankOfMarsThirdPartyService(); }
}
}
}
namespace CodeMentor.Patterns.GOF.Creational.AbstractFactory.Examples.Banking
{
public class BankOfNeptuneBankProviderService : BaseBankProviderService
{
public BankOfNeptuneBankProviderService(
IBankProviderServiceCredentials bankProviderServiceCredentials)
: base(bankProviderServiceCredentials)
{
}
public override BaseAccountProvider AccountProvider
{
get
{
return new BankOfNeptuneAccountProvider(
AuthorizationService.GetAuthorizationToken(
BankProviderServiceCredentials));
}
}
public override BaseAuthorizationService AuthorizationService
{
get { return new BankOfNeptuneAuthorizationService(); }
}
public override BaseThirdPartyService ThirdPartyService
{
get { return new BankOfNeptuneThirdPartyService(); }
}
}
}
Therefore, in order to create a BankProviderService, one is required to provide a PIN and the name of the Bank to the Atm static class. The Atm class exposes a Factory method that will be used to create the appropriate BankProviderService based on the provided bank name.
namespace CodeMentor.Patterns.GOF.Creational.AbstractFactory.Examples.Banking
{
public static class Atm
{
public enum Bank
{
BankOfMars,
BankOfNeptune
}
public static BaseBankProviderService Create(Bank bank, int PIN)
{
switch (bank)
{
case (Bank.BankOfMars):
{
// We could have used a factory method here to return
// the appropriate credentials
IBankProviderServiceCredentials credentials =
new DefaultBankProviderServiceCredentials(PIN);
return new BankOfMarsBankProviderService(credentials);
}
case (Bank.BankOfNeptune):
{
// We could have used a factory method here to return
// the appropriate credentials
IBankProviderServiceCredentials credentials =
new DefaultBankProviderServiceCredentials(PIN);
return new BankOfNeptuneBankProviderService(credentials);
}
}
throw new Exception("An invalid Bank was specified.");
}
}
}
The code to test the BankProviderService is as follows:
public static void TestBankOfMarsProviderService()
{
Console.WriteLine(
"-- Testing Bank Of Mars Bank Provider Service --");
Console.WriteLine();
BaseBankProviderService service = Atm.Create(
Atm.Bank.BankOfMars, 55555);
Console.WriteLine("Bank Provider Service: {0}",
service.GetType().Name);
BaseAccountProvider accountProvider =
service.AccountProvider;
Console.WriteLine("Account Provider: {0}",
accountProvider.GetType().Name);
Console.WriteLine("Account: {0}",
accountProvider.GetAccount("1234567890").GetType().Name);
BaseAuthorizationService authorizationService =
service.AuthorizationService;
Console.WriteLine("Authorization Service: {0}",
authorizationService.GetType().Name);
BaseThirdPartyService thirdPartyService =
service.ThirdPartyService;
Console.WriteLine("Third Party Service: {0}",
thirdPartyService.GetType().Name);
Console.WriteLine();
Console.WriteLine("-- End Test --");
}
public static void TestBankOfNeptuneBankProviderService()
{
Console.WriteLine(
"-- Testing Bank Of Neptune Bank Provider Service --");
Console.WriteLine();
BaseBankProviderService service = Atm.Create(
Atm.Bank.BankOfNeptune, 55555);
Console.WriteLine("Bank Provider Service: {0}",
service.GetType().Name);
BaseAccountProvider accountProvider = service.AccountProvider;
Console.WriteLine("Account Provider: {0}",
accountProvider.GetType().Name);
Console.WriteLine("Account: {0}",
accountProvider.GetAccount("1234567890").GetType().Name);
BaseAuthorizationService authorizationService =
service.AuthorizationService;
Console.WriteLine("Authorization Service: {0}",
authorizationService.GetType().Name);
BaseThirdPartyService thirdPartyService =
service.ThirdPartyService;
Console.WriteLine("Third Party Service: {0}",
thirdPartyService.GetType().Name);
Console.WriteLine();
Console.WriteLine("-- End Test --");
}
The result of the BankProviderService test is as follows:
Example 2 - Game
Many are familiar with RTS (Real Time Strategy) games like Starcraft, Warcraft, Command and Conquer, etc. One of the common things that one is required to do is build structures that will allow one to build units from the structures. So, in the spirit of RTS games, we are going to create a simple implementation of how one might use the combination of Factory Methods and Abstract Factories to create structures and units.
The following high-level uml diagram represents the Abstract Factory design that we will use for this example.

Our game has two types of species. The Gaea Federation and the Borg. Our abstract factory must allow us to create a Barracks, Headquarters and a WarRoom for the two species. The structures will determine what units may be created. Therefore, we will create a family of structures (products) along with a family of units (products for the structures). This example will demonstrate two possible implementations for the abstract factory.
For the first implementation we will use a Factory for each family of structures.
namespace CodeMentor.Patterns.GOF.Creational.AbstractFactory.Examples.Game
{
public abstract class BaseStructureFactory
{
protected BaseStructureFactory()
{
}
public abstract BaseBarracks Barracks { get; }
public abstract BaseHQ HQ { get; }
public abstract BaseWarRoom WarRoom { get; }
}
}
namespace CodeMentor.Patterns.GOF.Creational.AbstractFactory.Examples.Game
{
public class BorgStructureFactory : BaseStructureFactory
{
public BorgStructureFactory()
: base()
{
}
public override BaseBarracks Barracks
{
get { return new BorgBarracks(); }
}
public override BaseHQ HQ
{
get { return new BorgHQ(); }
}
public override BaseWarRoom WarRoom
{
get { return new BorgWarRoom(); }
}
}
}
namespace CodeMentor.Patterns.GOF.Creational.AbstractFactory.Examples.Game
{
public class GaeaFederationStructureFactory : BaseStructureFactory
{
public GaeaFederationStructureFactory()
: base()
{
}
public override BaseBarracks Barracks
{
get { return new GaeaFederationBarracks(); }
}
public override BaseHQ HQ
{
get { return new GaeaFederationHQ(); }
}
public override BaseWarRoom WarRoom
{
get { return new GaeaFederationWarRoom(); }
}
}
}
The BaseStructureFactory will allow one to create the required game structures. The game structures are shown below.

namespace CodeMentor.Patterns.GOF.Creational.AbstractFactory.Examples.Game.Structures
{
public abstract class BaseBarracks
{
public enum Unit
{
FootmanSoldier,
Insidious,
StarshipTrooper
}
protected BaseBarracks()
{
}
public abstract BaseBarracksUnit CreateUnit(Unit unit);
public abstract string Name { get; }
public abstract void Upgrade();
}
}
namespace CodeMentor.Patterns.GOF.Creational.AbstractFactory.Examples.Game.Structures
{
public class BorgBarracks : BaseBarracks
{
public BorgBarracks()
: base()
{
}
public override BaseBarracksUnit CreateUnit(Unit unit)
{
switch (unit)
{
case(Unit.Insidious):
return new Insidious();
default:
throw new Exception(String.Format(
"Unit '{0}' is an invalid Borg Barracks Unit.",
unit.ToString()));
}
}
public override string Name
{
get { return "Hive"; }
}
public override void Upgrade()
{
Console.WriteLine("Upgrading the Borg '{0}'.", Name);
}
}
}
namespace CodeMentor.Patterns.GOF.Creational.AbstractFactory.Examples.Game.Structures
{
public class GaeaFederationBarracks : BaseBarracks
{
public GaeaFederationBarracks()
: base()
{
}
public override BaseBarracksUnit CreateUnit(Unit unit)
{
switch (unit)
{
case(Unit.FootmanSoldier):
return new FootmanSoldier();
case(Unit.StarshipTrooper):
return new StarshipTrooper();
default:
throw new Exception(String.Format(
"Unit '{0}' is an invalid Gaea Barracks Unit.",
unit.ToString()));
}
}
public override string Name
{
get { return "Playpen"; }
}
public override void Upgrade()
{
Console.WriteLine("Upgrading the Gaea Federation '{0}'.", Name);
}
}
}

namespace CodeMentor.Patterns.GOF.Creational.AbstractFactory.Examples.Game.Structures
{
public abstract class BaseHQ
{
public enum Unit
{
Ghost,
Spy
}
protected BaseHQ()
{
}
public abstract BaseHQUnit CreateUnit(Unit unit);
public abstract void Research(Weapon weapon);
}
}
namespace CodeMentor.Patterns.GOF.Creational.AbstractFactory.Examples.Game.Structures
{
public class BorgHQ : BaseHQ
{
public BorgHQ()
: base()
{
}
public override BaseHQUnit CreateUnit(Unit unit)
{
switch(unit)
{
case(Unit.Ghost):
return new Ghost();
default:
throw new Exception(String.Format(
"Unit '{0}' is an invalid Borg HQ Unit.",
unit.ToString()));
}
}
public override void Research(Weapon weapon)
{
Console.WriteLine("Researching Borg Weapon '{0}'.", weapon.Name);
}
}
}
namespace CodeMentor.Patterns.GOF.Creational.AbstractFactory.Examples.Game.Structures
{
public class GaeaFederationHQ : BaseHQ
{
public GaeaFederationHQ()
: base()
{
}
public override BaseHQUnit CreateUnit(Unit unit)
{
switch (unit)
{
case (Unit.Spy):
return new Spy();
default:
throw new Exception(String.Format(
"Unit '{0}' is an invalid Gaea HQ Unit.",
unit.ToString()));
}
}
public override void Research(Weapon weapon)
{
Console.WriteLine("Researching Gaea Federation Weapon '{0}'.", weapon.Name);
}
}
}

namespace CodeMentor.Patterns.GOF.Creational.AbstractFactory.Examples.Game.Structures
{
public abstract class BaseWarRoom
{
public enum Unit
{
Admiral,
Queen
}
protected BaseWarRoom()
{
}
public abstract BaseWarRoomUnit CreateUnit(Unit unit);
public abstract void GetIntel(Location location);
public abstract string Name { get; }
}
}
namespace CodeMentor.Patterns.GOF.Creational.AbstractFactory.Examples.Game.Structures
{
public class BorgWarRoom : BaseWarRoom
{
public BorgWarRoom()
: base()
{
}
public override BaseWarRoomUnit CreateUnit(Unit unit)
{
switch(unit)
{
case(Unit.Queen):
return new Queen();
default:
throw new Exception(String.Format(
"Unit '{0}' is an invalid Borg WarRoom Unit.",
unit.ToString()));
}
}
public override void GetIntel(Location location)
{
Console.WriteLine("'{0}' is gathering Borg Intel for '{1}'.", Name, location.Name);
}
public override string Name
{
get { return "Temple of Truth"; }
}
}
}
namespace CodeMentor.Patterns.GOF.Creational.AbstractFactory.Examples.Game.Structures
{
public class GaeaFederationWarRoom : BaseWarRoom
{
public GaeaFederationWarRoom()
: base()
{
}
public override BaseWarRoomUnit CreateUnit(Unit unit)
{
switch(unit)
{
case(Unit.Admiral):
return new Admiral();
default:
throw new Exception(String.Format(
"Unit '{0}' is an invalid Gaea WarRoom Unit.",
unit.ToString()));
}
}
public override void GetIntel(Location location)
{
Console.WriteLine("'{0}' is gathering Gaea Intel for '{1}'.", Name, location.Name);
}
public override string Name
{
get { return "Games Room"; }
}
}
}
The second implementation of a Factory is to make each structure a Factory that exposes a Factory Method to create units. Therefore, we will not have a Factory for each type of unit. Therefore, one can add additional units without having to add additional factories. However, one will be required to modify the relevant Factory Method to return the appropriate structure. The Factory Method that I am referring to can be seen in the diagrams above. The name of the Factory Method is CreateUnit(Unit unit). The Factory Method uses an enumeration to determine what unit it must create. The Units that are available for creation are as follows.
namespace CodeMentor.Patterns.GOF.Creational.AbstractFactory.Examples.Game.Units
{
public abstract class BaseBarracksUnit
{
protected BaseBarracksUnit()
{
}
public abstract void Attack();
public abstract string Name { get; }
}
}
namespace CodeMentor.Patterns.GOF.Creational.AbstractFactory.Examples.Game.Units
{
public class FootmanSoldier : BaseBarracksUnit
{
public FootmanSoldier()
: base()
{
}
public override void Attack()
{
Console.WriteLine("Footmen Soldier '{0}' attacks.", Name);
}
public override string Name
{
get { return "Incredible Footie"; }
}
}
}
namespace CodeMentor.Patterns.GOF.Creational.AbstractFactory.Examples.Game.Units
{
public class Insidious : BaseBarracksUnit
{
public Insidious()
: base()
{
}
public override void Attack()
{
Console.WriteLine("Insidious '{0}' attacks.", Name);
}
public override string Name
{
get { return "Slyborg"; }
}
}
}
namespace CodeMentor.Patterns.GOF.Creational.AbstractFactory.Examples.Game.Units
{
public class StarshipTrooper : BaseBarracksUnit
{
public StarshipTrooper()
: base()
{
}
public override void Attack()
{
Console.WriteLine("Starship Trooper '{0}' attacks.", Name);
}
public override string Name
{
get { return "Spock"; }
}
}
}

namespace CodeMentor.Patterns.GOF.Creational.AbstractFactory.Examples.Game.Units
{
public abstract class BaseHQUnit
{
protected BaseHQUnit()
{
}
public abstract void UpgradeIntelligence();
}
}
namespace CodeMentor.Patterns.GOF.Creational.AbstractFactory.Examples.Game.Units
{
public class Ghost : BaseHQUnit
{
public Ghost()
: base()
{
}
public override void UpgradeIntelligence()
{
Console.WriteLine("Upgrading Ghost Intelligence.");
}
}
}
namespace CodeMentor.Patterns.GOF.Creational.AbstractFactory.Examples.Game.Units
{
public class Spy : BaseHQUnit
{
public Spy()
: base()
{
}
public override void UpgradeIntelligence()
{
Console.WriteLine("Upgrading Spy Intelligence.");
}
}
}

namespace CodeMentor.Patterns.GOF.Creational.AbstractFactory.Examples.Game.Units
{
public abstract class BaseWarRoomUnit
{
protected BaseWarRoomUnit()
{
}
public abstract void UpgradeStrategySkill();
}
}
|