Pro .NET 2.0 Code And Design Standards In CSharp (2006) [eng]
.pdf186C H A P T E R 1 0 ■ C R E AT I O N A L PAT T E R N S
•A number of Radiator objects derived from the abstract Radiator class
•An abstract RadiatorCap class
•A number of RadiatorCap objects derived from the abstract Radiator class
•A WorkOrder class
•Client code that, through passing a set of abstract factories to an instance of a WorkOrder, is able to indirectly control the creation of sets of factories (Briscoe, Detroit, and McCord) that build sets of products (Radiators and RadiatorCaps)
Now let’s code the Abstract Factory pattern.
Pattern Code
The essence of the design lies in the way in which the abstract RadiatorFactory class leverages abstract classes (Radiator and RadiatorCap), delegating or deferring implementation and coupling to RadiatorFactory objects. The WorkOrder class plays the role of a context that enables the client to distance itself from the build process. Notice that it is when the RadiatorFactory class is implemented or instantiated that there is the first commitment to a set of factories types (Briscoe, Detroit, and McCord). In turn, these factory types commit to an implementation of a set of product types (Radiators and RadiatorCaps). Observe the regimentation of control throughout the design: the sets of like products are encapsulated within a given factory, which itself is treated as an abstraction through which the client indirectly manipulates the whole process without being coupled to factory or product types.
RadiatorFactory Class
public abstract class RadiatorFactory
{
public abstract Radiator BuildRadiator(); public abstract RadiatorCap BuildRadiatorCap();
}
BriscoeRadiatorFactory Class
public class BriscoeRadiatorFactory: RadiatorFactory
{
public override Radiator BuildRadiator()
{
Radiator rad = new BriscoeRadiator(); rad.RadiatorBrand();
return rad;
}
C H A P T E R 1 0 ■ C R E AT I O N A L PAT T E R N S |
187 |
public override RadiatorCap BuildRadiatorCap()
{
RadiatorCap cap = new BriscoeRadiatorCap(); cap.RadiatorCapBrand();
return cap;
}
public BriscoeRadiatorFactory() {;}
}
DetroitRadiatorFactory Class
public class DetroitRadiatorFactory: RadiatorFactory
{
public override Radiator BuildRadiator()
{
Radiator rad = new DetroitRadiator(); rad.RadiatorBrand();
return rad;
}
public override RadiatorCap BuildRadiatorCap()
{
RadiatorCap cap = new DetroitRadiatorCap(); cap.RadiatorCapBrand();
return cap;
}
public DetroitRadiatorFactory() {;}
}
McCordRadiatorFactory Class
public class McCordRadiatorFactory: RadiatorFactory
{
public override Radiator BuildRadiator()
{
Radiator rad = new McCordRadiator(); rad.RadiatorBrand();
return rad;
}
public override RadiatorCap BuildRadiatorCap()
188 C H A P T E R 1 0 ■ C R E AT I O N A L PAT T E R N S
{
RadiatorCap cap = new McCordRadiatorCap(); cap.RadiatorCapBrand();
return cap;
}
public McCordRadiatorFactory() {;}
}
Radiator Class
public abstract class Radiator
{
public abstract void RadiatorBrand();
}
BriscoeRadiator Class
public class BriscoeRadiator: Radiator
{
public override void RadiatorBrand()
{
Console.WriteLine ("Briscoe Radiator.");
}
public BriscoeRadiator() {;}
}
DetroitRadiator Class
public class DetroitRadiator:Radiator
{
public override void RadiatorBrand()
{
Console.WriteLine ("Detroit Radiator.");
}
public DetroitRadiator() {;}
}
C H A P T E R 1 0 ■ C R E AT I O N A L PAT T E R N S |
189 |
McCordRadiator Class
public class McCordRadiator: Radiator
{
public override void RadiatorBrand()
{
Console.WriteLine ("McCord Radiator.");
}
public McCordRadiator() {;}
}
RadiatorCap Class
public abstract class RadiatorCap
{
public abstract void RadiatorCapBrand();
}
BriscoeRadiatorCap Class
public class BriscoeRadiatorCap: RadiatorCap
{
public override void RadiatorCapBrand()
{
Console.WriteLine("Briscoe Radiator cap.");
}
public BriscoeRadiatorCap() {;}
}
DetroitRadiatorCap Class
public class DetroitRadiatorCap: RadiatorCap
{
public override void RadiatorCapBrand()
{
Console.WriteLine("Detroit Radiator cap.");
}
190 C H A P T E R 1 0 ■ C R E AT I O N A L PAT T E R N S
public DetroitRadiatorCap() {;}
}
McCordRadiatorCap Class
public class McCordRadiatorCap: RadiatorCap
{
public override void RadiatorCapBrand()
{
Console.WriteLine("McCord Radiator cap.");
}
public McCordRadiatorCap() {;}
}
WorkOrder Class
public class WorkOrder
{
public void AssembleRadiator(Factory fact)
{
Radiator rad = fact.BuildRadiator(); RadiatorCap cap = fact.BuildRadiatorCap(); this.Assemble();
}
private void Assemble()
{
Console.WriteLine ("Assembling Radiator and cap."); Console.WriteLine();
}
public WorkOrder() {;}
}
Client Code
In the client code, we see the Abstract Factory pattern at work. We test the effectiveness of the design pattern, which enables client code to indirectly control the build process through a set of factories and a set of products, while ensuring that it is decoupled from factory and product implementations.
C H A P T E R 1 0 ■ C R E AT I O N A L PAT T E R N S |
191 |
class Client
{
static void Main(string[] args)
{
Factory factoryOne = new BriscoeRadiatorFactory(); WorkOrder workOne = new WorkOrder(); workOne.AssembleRadiator(factory1);
/* With the Abstract Factory pattern, The Model T domain can easily
switch suppliers. It simply stops calling the Briscoe Radiator
factory, and commences calling the Detroit and McCord Radiator
factories, to supply radiators. For each new supplier, respective
Radiator, Cap and Factory classes need to be added. Which is a good
thing, because shortly after changing from Briscoe, The Model T
domain made a further change and began to fit only Ford radiators.*/
Factory factoryTwo = new DetroitRadiatorFactory(); WorkOrder workTwo = new WorkOrder(); workTwo.AssembleRadiator(factoryTwo);
Factory factoryThree = new McCordRadiatorFactory(); WorkOrder workThree = new WorkOrder(); workThree.AssembleRadiator(factoryThree);
}
}
Console Output
Briscoe Radiator.
Briscoe Radiator cap.
Assembling Radiator and cap.
Detroit Radiator.
Detroit Radiator cap.
Assembling Radiator and cap.
192C H A P T E R 1 0 ■ C R E AT I O N A L PAT T E R N S
McCord Radiator. MsCord Radiator cap.
Assembling Radiator and cap.
Press any key to continue
The Standard: Abstract Factory Design Pattern
The standard acknowledges the use of the Abstract Factory design pattern when there is a requirement not to couple the client to an implementation that creates sets or families of object, yet to let the client indirectly control the build process.
Factory Method Pattern
A Factory Method pattern encapsulates a design feature when a class can’t foresee what objects it will be required to create and so delegates the task to subclasses. In everyday life, examples of a factory pattern include a translation service that delegates the task of translating news stories to a variety of specialist language translators; or a visual display controller that delegates the task of displaying data to display objects, which in turn display data in text or graphic format.
What
A Factory Method pattern is a design that defines an interface for creating objects but delegates the choice of what objects to create to subclasses.
Where
A Factory Method pattern is used where there is a design problem where a creator class is required to be decoupled from creating specific objects.
Why
In many domains there is a requirement for flexibility in creating a variety of objects and to localize the functionality to a set of specialized subclasses.
How
The creator class delegates to its subclasses, which override its factory method to create specific types, which in turn create content objects.
C H A P T E R 1 0 ■ C R E AT I O N A L PAT T E R N S |
193 |
Pattern Example
In the Model T domain, there is client code that manages composing two publications: a new car catalog and an owners’ technical manual.
The part of the problem we are focusing on is how to efficiently coordinate the tasks of creating different content and different arrangements in different publications: a page in a catalog is arranged with features and picture content, whereas a page in a technical manual is arranged with technical, picture, and instruction content.
To code this routine, we create an abstract page class (Page) that includes an abstract factory method (AddContent()) that the subclasses (CatalogPage and ManualPage) will override as they make a choice on which content to add to the respective page. An abstract Content class offers an interface to manage the creation of content by subclasses (FeaturesContent, InstructionContent,
PictureContent, and TechnicalContent). The factory method (AddContent()), which resides in the Page sub-classes (CatalogPage and ManualPage), makes the choice of what Content classes to instantiate in the respective page. That is the Factory Method pattern!
We shall now look at the Factory Method pattern in a UML diagram (see Figure 10-2) and then implement the pattern in code.
UML
Figure 10-2. Factory Method pattern
194 C H A P T E R 1 0 ■ C R E AT I O N A L PAT T E R N S
Key Code Ingredients
The code for the Factory Method pattern has the following key ingredients:
•An abstract Content class
•Several classes that derive from Content class
•FeaturesContent class
•InstructionContent class
•PictureContent class
•TechnicalContent class
•An abstract Page class
•An abstract factory method
•Several classes that derive from Page class
•CatalogPage class
•An override of the factory method
•ManualPage class
•An override of the factory method
•Client class
•A call to the factory method of an instantiated Page class Now let’s code the Factory Method pattern.
Pattern Code
The essence of the design lies in the Page class, where the factory method (AddContent()) is modified as abstract, which enables flexibility in the design of subclasses. Notice the role of Content class: it merely acts as an interface from which specialized content is derived (picture content and technical content, etc.). The subclasses (CatalogPage and ManualPage) specialize the class by choosing content and sequencing the arrangement of content on the page.
Content Class
public abstract class Content
{
public abstract void SomeContent();
}
C H A P T E R 1 0 ■ C R E AT I O N A L PAT T E R N S |
195 |
FeaturesContent Class
public class FeaturesContent: Content
{
public override void SomeContent()
{
Console.WriteLine("Technical content.");
}
public FeaturesContent() {;}
}
InstructionContent Class
public class InstructionContent: Content
{
public override void SomeContent()
{
Console.WriteLine("Instruction content.");
}
public InstructionContent() {;}
}
PictureContent Class
public class PictureContent: Content
{
public override void SomeContent()
{
Console.WriteLine("Picture content.");
}
public PictureContent() {;}
}