a DotNetStyling - .Net World by Armen Ayvazyan : Abstract Factory Design Pattern
Welcome to DotNetStyling Sign in | Join | Help
Add to Technorati Favorites Add to Google Reader or Homepage Add to My AOL Subscribe in FeedLounge Subscribe in Bloglines Add to Excite MIX Add to flurry Add to Pageflakes Subscribe in NewsGator Online


Abstract Factory Design Pattern

Theory

Abstract Factory provides interface for creating set of objects without specifying concrete implementation. Abstract Factory uses abstract classes and decouples concrete implementation from the system.  It brings flexibility to easily wire up different set of objects based on specified abstraction.

Abstract Factory helps to implement scenario where different set of products have the same implementation in application.

 

Diagram

image 

 

Client class instead of pointing to concrete set of products {ConcreteProductA1, ConcreteProductB1} or {ConcreteProductA2, ConcreteProductB2} works with theirs abstraction {ProductABase, ProductBBase}.

Concrete factories are responsible for creating set of concrete products.

 

Implementation

 

ProductA

image

 

public abstract class ProductABase

{

      public abstract void MethodA();

}

 

public sealed class ConcreteProductA1 : ProductABase

{

      public override void MethodA()

      {

            Console.WriteLine("MethodA of A1 has been called");

      }

}

public sealed class ConcreteProductA2 : ProductABase

      public override void MethodA() 
     
            Console.WriteLine("MethodA of A2 has been called"); 
      }
}

 

 
ProductB

 image

 

public abstract class ProductBBase
{
     public abstract void MethodB();
}

 

public sealed class ConcreteProductB1 : ProductBBase

     public override void MethodB() 
    
           Console.WriteLine("MethodB on B1 has been started."); 
     }
}

public sealed class ConcreteProductB2 : ProductBBase

     public override void MethodB() 
    
           Console.WriteLine("MethodB on B2 has been started."); 
     }
}

 

 

Factories

To prevent user for making mistake in passing wrong set of products we will introduce factories which will be responsible for creating correct combination of products.

image

 

Each Factory ensures that only specified pair of products will be instantiated and set to the Client.

public abstract class FactoryBase

{

     public abstract ProductABase CreateProductA();

     public abstract ProductBBase CreateProductB();

}

 
 

public class ConcreteFactory1 : FactoryBase

{

     public override ProductABase CreateProductA()

     {

           return new ConcreteProductA1();

     }

 

     public override ProductBBase CreateProductB()

    
           return new ConcreteProductB1(); 
     }
}

 

public class ConcreteFactory2 : FactoryBase

     public override ProductABase CreateProductA() 
    
           return new ConcreteProductA2(); 
    

     public override ProductBBase CreateProductB() 
    
           return new ConcreteProductB2(); 
     }
} 

 
 
 
Client

image

public sealed class Client

     private ProductABase _productA; 
     private ProductBBase _productB; 
            
     public Client(FactoryBase _factory) 
    
           _productA = _factory.CreateProductA(); 
           _productB = _factory.CreateProductB(); 
     }

     public void ExecuteProducts() 
    
           _productA.MethodA(); 
           _productB.MethodB(); 
     }
}

 

Usage

This is  how it used in application

FactoryBase factory = new ConcreteFactory1();

Client client = new Client(factory);  

client.ExecuteProducts();

 

This is an output of above code execution:

image

It is enough to change just one line of code and we will get implementation of another set of products. 

FactoryBase factory = new ConcreteFactory2();
...
... 
      


image

 

 

Example

 

Use case scenario

We have a hardware department inside of the company which delivers products for employees needs: desktop boxes, monitors, mice, keyboard, etc. They also builds and delivers a Computer set (bundle of products).

Due to fact that we have various products of the same type, we can make many Computers with different combination of products.

To simplify our example lets assume that Computer contains only desktop box and monitor.

 

UML Diagram

This is the UML diagram which describes Computer set thru Abstract Factory model.

 

image

 

 

Implementation of Monitors

MonitorBase class represents a shell for all existing monitors. It contains just one member:

  • MonitorSize - abstract readonly property which returns size of monitor in inches

There are two types of monitors classes used in our example:

  • LCDSumsung21
  • LCDDell19

 

image

 

public abstract class MonitorBase

     public abstract int MonitorSize { get;}
}

public sealed class LCDDell19 : MonitorBase
{
     public override int MonitorSize 
    
           get { return 19; } 
     }
}

  
public sealed class LCDSamsung21 : MonitorBase
{
public override int MonitorSize
{ get { return 21; } 
}
}

Implementation of Desktop boxes

DesktopBoxBase class represents all desktop boxes. It contains a couple of members:

  • CPU - abstract readonly property which returns type of CPU used in desktop box
  • HDD - abstract readonly propery which returns type and size of hard drive used in box
  • Memory - abstract readonly property which returns type and size of memory used in box
  • Start - abstract method
  • Shutdown - abstract method

In this example we will use two type of boxes. To simplify example we will call them AMDBox and IntelBox. Both classes are inherited from DesktopBoxBase and contain implementation of members we listed above.

 

image

 

public abstract class DesktopBoxBase
{
     public abstract string CPU{ get;}
     public abstract string Memory{ get;}
     public abstract string HDD { get;}  

 

     public abstract void Start(); 
     public abstract void Shutdown();
}

 

public sealed class AMDBox : DesktopBoxBase

     public override void Start() 
    
           Console.WriteLine("AMDBox has been started."); 
     }  

 

     public override void Shutdown() 
     {
           Console.WriteLine("AMDBox has been shutted down."); 
     }  

 

     public override string CPU 
    
           get { return "AMD 2800+"; } 
     }

     public override string Memory 
    
           get { return "DDR 2x512Mb";} 
     }

     public override string HDD 
    
           get { return "SATA 2x160Gb";} 
     }
}
 
 

public sealed class IntelBox : DesktopBoxBase
{
     public override void Start() 
    
           Console.WriteLine("IntelBox has been started."); 
     } 

     public override void Shutdown() 
    
           Console.WriteLine("IntelBox box has been shutted down.");
     }

     public override string CPU 
    
           get { return "Intel Core2Quad"; } 
      

     public override string Memory
     {
           get { return "DDR 2x1024Mb"; } 
     }  

     public override string HDD 
     {

           get { return "SATA 250Gb"; }

     }
}

 

Implementation of Factory

As you can see in diagram, there is a abstract ComputerFactory class which contains two abstract methods which are responsible for creating concrete products for a particular set: CreateComputerBox and CreateMonitor.

There is one to one relationship between product set (or bundle) and concrete factory. Each concrete factory responsible for delivering appropriate products to Computer class.

image

 

public abstract class ComputerFactory
{
     public abstract DesktopBoxBase CreateComputerBox(); 
     public abstract MonitorBase CreateMonitor();
}

public sealed class DeveloperPC : ComputerFactory

     public override DesktopBoxBase CreateComputerBox() 
    
           return new IntelBox(); 
     }

 

     public override MonitorBase CreateMonitor() 
    
           return new LCDDell19(); 
     }
}

 

public sealed class ManagerPC : ComputerFactory
{
     public override DesktopBoxBase CreateComputerBox() 
    
           return new AMDBox(); 
     }  

 

     public override MonitorBase CreateMonitor()

     {

           return new LCDSamsung21();

     }

}

 

 

Computer class

image

 

public sealed class Computer

{

 

     private DesktopBoxBase _box;

     public DesktopBoxBase DesktopBox

     {

           get { return _box; }

     }

     private MonitorBase _monitor;  
     public MonitorBase Monitor 
    
           get { return _monitor; } 
     }

     public Computer(ComputerFactory cf)
    
           _box = cf.CreateComputerBox(); 
           _monitor = cf.CreateMonitor(); 
     }  

 

     public void WriteOutConfiguration()
    
           Console.WriteLine("CPU: {0}", _box.CPU); 
           Console.WriteLine("Memory: {0}", _box.Memory); 
           Console.WriteLine("HDD, {0}", _box.HDD); 
     }  

 

     public void Start() 
    
           _box.Start(); 
     }  

 

     public void Shutdown() 
    
           _box.Shutdown(); 
     }
}

 

Usage

 

ComputerFactory factory = new DeveloperPC();
Computer computer = new Computer(factory);

Console.WriteLine("Size of display is {0} inches"
                  computer.Monitor.MonitorSize); computer.WriteOutConfiguration();
computer.DesktopBox.Start();
computer.DesktopBox.Shutdown();

 

image

 

It is enough to change just one line of code and we will get functionality of another computer:

ComputerFactory factory = new ManagerPC();

image

 

 

Conclusion

 

Advantages

  • Without touching implementation we can add new set of products. We just need to implement new concrete factory and instantiate it instead of existing.

 

Disadvantages.

 

  • All products of the same type should contain the same members. It is not possible (or too problematic) to add and use new member for only one product. For instance if we need Dell19 monitors to have additional "Color" property we have to implement it for all type for monitors inherited from MonitorBase class.
  • All factories responsible to build same type of products. For instance we used factory to build Computer with "desktop + monitor" set of products. We cannot add factory which will have "desktop + monitor + mouse". Either all factories should build "desktop + monitor + mouse" or all should build "desktop + monitor". 

 

kick it on DotNetKicks.com

Posted: 25. listopadu 2007 22:28 by Armen Ayvazyan

Comments

New Comments to this post are disabled