Factory Method

advertisement
Factory Method
Explained
Intent
Define an interface for creating an object, but let
subclasses decide which class to instantiate.
Factory Method lets a class defer instantiation to
subclasses.
a.k.a. Virtual Constructor
The main intent of the virtual constructor idiom in C++
is to create a copy of an object or a new object without
knowing its concrete type and this is exactly what the
Factory Method does
Can a constructor be virtual?





2
Motivation
Frameworks use abstract classes to define and maintain
relationships between objects
A framework is often responsible for creating these
objects as well
They must instantiate classes but only know about
abstract classes - which they cannot instantiate
Factory method encapsulates knowledge of which
subclass to create - moves this knowledge out of the
framework




3
Motivation (Cont’d)
Consider a framework for presenting multiple documents
to the user
Key abstraction in this framework are Application and
Document classes
Both classes are abstract and realized in subclasses
Application class is responsible for managing and creating
the Documents as and when required.




4
Motivation (Cont’d)
The particular Document subclass to instantiate is
application specific, and
The Application class can’t predict the subclass of
Document to instantiate. As it only knows when a new
document should be created.
NOT
What kind of a Document to create.
This creates a dilemma…




5
Motivation (Cont’d)

Factory method solves this problem. It encapsulates the
knowledge of which Document to create and moves this
knowledge out of the framework.
factory method
6
Motivation (Cont’d)
Application subclasses redefine an abstract
CreateDocument operation to return Document
subclasses
Once an Application subclass is instantiated, it can then
instantiate application specific Documents
We call CreateDocument a factory method as it’s
responsible for manufacturing a object.



7
Applicability
Use the Factory Method pattern when
 A class can’t anticipate the class of objects it must
create
 A class wants it’s subclasses to specify the objects it
creates
 Classes delegate responsibility to one of several
helper subclasses, and you want to localize the
knowledge of which helper subclass is the delegate.

8
Structure
9
Participants

Product (Document)


Concrete Product (MyDocument)


Implements the product interface
Creator (Application)




defines the interface of objects the factory method creates
declares the factory method which return a Product type.
May also define a default implementation of the factory
method that returns a default ConcreteProduct object
May call the factory method to create a Product object.
Concrete Creator (MyApplication)

10
Overrides the factory method to return Concrete Product
Collaborations

Creator relies on it’s subclasses to define the factory
method so that it returns an instance of the appropriate
ConcreteProduct(Subclasses of Product)
11
Consequences



Factory methods eliminate the need to bind application
specific classes into your code
The code only deals with the Product interface; therefore
it can work with any user defined ConcreteProduct
classes.
A potential disadvantage of using Factory pattern is that
client also has to subclass the Creator class in order to
create a particular ConcreteProduct object.
12
Consequences (Cont’d)

Provides hooks for subclasses



13
Creating objects inside a class with a factory method is always
more flexible than creating an object directly
Factory method gives subclasses a hook for providing an
extended version of an object
Example: the Document class could define a factory method
called CreateFileDialog for opening an existing document.
Consequences (Cont’d)

Connects Parallel Class Hierarchies


14
Parallel Class hierarchies result when a class delegates some of
it’s responsibilities to a separate class
Clients can use factory methods to connect between parallel
class hierarchies
Consequences (Cont’d)





The figure class provides a CreateManipulator factory method
that lets clients create a Figure’s corresponding Manipulator
Figure subclasses override this method to return an instance
of the required manipulator subclass
Alternatively the Figure class may implement
CreateManipulator to return a default manipulator. The figure
subclasses may inherit the default.
The figure classes that do so need no corresponding
Manipulator subclasses. Hence partially parallel class
hierarchies
This is how the factory method defines connection between
these class hierarchies
15
Implementation Styles

Two Major Varieties




16
The case when the Creator class is an abstract class and does
not provide an implementation of factory method
The case when the Creator class is a concrete class and has a
default implementation of the factory method
The first case requires subclasses to define an implementation
as there is no reasonable default
In the second case the subclasses or concrete Creator uses
factory method primarily for flexibility.
Implementation Styles (Cont’d)

Parameterized factory methods




create multiple kinds of products
the factory method takes a parameter that identifies the kind
of object to create
the object share the Product interface
Naming conventions

17
The name of the Factory method in code should clearly mark
its purpose.
Implementation

So the situation is that you have a set of related concrete
classes and there may be some conditions to call any one
of them
18
Implementation (Cont’d)






When we see code like this we know that when it comes to
changes and extensions, we will have to re-open this code and
examine what needs to be added or deleted.
Often this type of code ends up in several parts of an
application making maintenance and updates more difficult and
error prone.
By coding to an interface we know we can insulate ourselves
with lot of changes occurring down the road
However if you have concrete classes then you might end up
in trouble if more concrete classes are added
In other words code would not be closed for modification
So what’s the solution?
19
Implementation (Cont’d)



Remember the design principle “Identify the aspects that
vary and separate them from what stays the same”
We will now see an example implementation of Pizza
shop to illustrate the application of this design principle
We will have a function of OrderPizza() to determine one
type of Pizza and run different processes for making a
pizza.
20
Implementation (Cont’d)
public class Pizza
{
Pizza pizza; //Declarations
public Pizza() { } //Constructor of Pizza
//Declarations of Pizza Functions
public virtual void Prepare() {}
public virtual void Bake() { }
public virtual void Cut() { }
public virtual void Box() { }
//Method of Ordering a Pizza
public void OrderPizza() {
pizza = new Pizza();
pizza.Prepare();
pizza.Bake();
pizza.Cut();
pizza.Box();
} //Return only one type of Pizza
21
Implementation (Cont’d)

The concrete classes of Pizza like cheese pizza and pepperoni pizza
public class CheesePizza : Pizza
{
public CheesePizza() {
Console.WriteLine("Constructing CHEESE PIZZA"); }
public override void Prepare()
{ Console.WriteLine("Preparing CHEESE PIZZA"); }
public override void Bake()
{ Console.WriteLine("Baking CHEESE PIZZA"); }
public override void Cut()
{ Console.WriteLine("Cutting CHEESE PIZZA"); }
public override void Box()
{ Console.WriteLine("Boxing CHEESE PIZZA"); }
}
22
Implementation (Cont’d)
public class PepperoniPizza : Pizza
{
public PepperoniPizza() {
Console.WriteLine("Constructing Pepperoni Pizza"); }
public override void Prepare()
{ Console.WriteLine("Preparing Pepperoni Pizza"); }
public override void Bake()
{ Console.WriteLine("Baking Pepperoni Pizza"); }
public override void Cut()
{ Console.WriteLine("Cutting Pepperoni Pizza"); }
public override void Box()
{ Console.WriteLine("Boxing Pepperoni Pizza"); }
}
23
Implementation (Cont’d)

Now we will add code that determines different types of pizza
and then goes about making it. The order pizza function will
change
public void OrderPizza(String type){
if (type.Equals("Cheese")){
pizza = new CheesePizza(); //Calling object of Subclass for Cheese Pizza
}
else if (type.Equals("Pepperoni"))
{
pizza = new PepperoniPizza();//Calling object of Subclass for Pepperoni Pizza
}
pizza.Prepare();
pizza.Bake();
pizza.Cut();
pizza.Box();
}
24
Implementation (Cont’d)





We have now passed the type of pizza (string type) to
OrderPizza function
Based on the type of pizza we instantiate the correct
concrete class and assign it to the pizza instance variable.
Note that each pizza here would have to implement the
pizza interface.
So each pizza type knows how to prepare itself.
But the pressure in on to add or subtract pizza types
25
Implementation (Cont’d)
public void OrderPizza(String type){
if (type.Equals("Cheese")){
This part of code is
changing
pizza = new CheesePizza();
}
else if (type.Equals("Pepperoni")){
pizza = new PepperoniPizza();
}
// “here we can add more pizza types”
pizza.Prepare();
pizza.Bake();
This part of code is supposed
to remain unchanged
pizza.Cut();
pizza.Box();
}
26
Implementation (Cont’d)





Clearly we can now make out what’s variable in our code
and we need to separate it
What we can do is that place the object creation code
into another object (class) whose sole purpose is to
create different types of pizza
This object can be called a SimplePizzaFactory
Once we have a factory the OrderPizza() becomes a
client of that factory. Anytime it needs a pizza it asks the
factory to make one
OrderPizza will get a correct pizza and would call
prepare(),bake(),cut() and box()
27
Implementation (Cont’d)

Here is the new class SimplePizzaFactory
public class SimplePizzaFactory
{
public SimplePizzaFactory() { }
public Pizza CreatePizza(String type)//This method would be used by all to create new objects
{
Pizza pizza = null;
if (type.Equals("Cheese"))
{
pizza = new CheesePizza(); //Calling object of Subclass for Cheese Pizza
}
else if (type.Equals("Pepperoni"))
{
pizza = new PepperoniPizza();//Calling object of Subclass for Pepperoni Pizza
}
return pizza;
}
}
28
Implementation (Cont’d)

The orderpizza method also be moved out of the Pizza class and
would be changed as under
public class PizzaStore {
SimplePizzaFactory factory = new SimplePizzaFactory(); //Creates the factory
public PizzaStore() { }
public void OrderPizza(String type)
{
Pizza pizza;
pizza = factory.CreatePizza(type); //Get the correct pizza from Factory
pizza.Prepare();
pizza.Bake();
pizza.Cut();
pizza.Box();
}//Method of Ordering a Pizza
}
29
Implementation (Cont’d)
30
Implementation (Cont’d)

Now the Pizza class would be changed as under
public abstract class Pizza //Superclass Pizza
{
public Pizza() { } //Contructor of Pizza
//Declarations of Pizza Funtions
public virtual void Prepare() { }
public virtual void Bake() { }
public virtual void Cut() { }
public virtual void Box() { }
}
31
Implementation (Cont’d)

The calling program for our code
class Program
{
static void Main(string[] args)
{
PizzaStore pizzastore = new PizzaStore();// The client just knows the pizza store
pizzastore.OrderPizza("Pepperoni");
Console.ReadLine();
}
}
32
Quiz # 1


Elements of a Design Pattern with an example
Describe Scope Based Design Patterns Classification?
33
Download