Download as pptx, pdf, or txt
Download as pptx, pdf, or txt
You are on page 1of 55

Factory Design Patterns

CECS277
Fall 2017
Mimi Opkins
Factory Pattern

• Word of the Day = Factory

• Different Flavors
– Simple Factory
– Factory Method
– Abstract Factory

01/12/2022 2
What Pattern should we consider?
• We need to manage a shared network printer.

• We create an algorithm for renting movies online.


MoviesOnline.com and ObjectvilleMovies both use the exact
same algorithm, but MoviesOnline.com would like the
additional capability of displaying the next movie in the queue
after a movie is rented.

• You are creating a character for a computer game. You want


the character to be able to support different victory dances.
The computer should be able to assign different victory dances
during game play.
01/12/2022 3
Pizza Store in Objectville
We need a pizza store that can create pizza.
The customer will order a specific type of pizza:
– Cheese
– Veggie
– Greek
– Pepperoni
– etc
Each order request is for one type of pizza only.

01/12/2022 4
PizzaStore in Objectville
• During the ordering of a Pizza, we need to perform certain actions
on it:
– Prepare
– Bake
– Cut
– Box

• We know that all Pizzas must perform these behaviors. In addition,


we know that these behaviors will not change during runtime . (i.e. the
Baking time for a Cheese Pizza will never change!)

• Question: Should these behaviors (prepare, bake, etc) be


represented using Inheritance or Composition?
01/12/2022 5
PizzaStore in Objectville (pg 112 top)
public Pizza orderPizza(String type) {

This method is responsible for


Pizza pizza = new Pizza();
creating the pizza.
pizza.prepare();
It calls methods to prepare,
pizza.bake();
bake, etc.
pizza.cut();
pizza.box(); Pizza is returned to caller.

return pizza;
}

• Creating an instance of Pizza() doesn’t make sense


here because we know there are different types of
Pizza.
01/12/2022 6
PizzaStore in Objectville
A parameter
indicating type
public Pizza orderPizza(String type) {

if (type.equals("cheese")) {
pizza = new CheesePizza();
Code that varies
} else if (type.equals("pepperoni")) {
pizza = new PepperoniPizza();

pizza.prepare();
pizza.bake(); Code that stays
pizza.cut(); the same
pizza.box();
return pizza;
}

01/12/2022 7
PizzaStore in Objectville (cont)

• Pressure is on for change…


• Now we get some new types of Pizza (Clam, Veggie)
• Every time there is a change, we would need to break
into this code and update the If/Else statement. (and
possibly introduce bugs in our existing code).

01/12/2022 8
Solution?
Move the creation of Pizzas into a separate object!
public class SimplePizzaFactory {

public Pizza createPizza(String type) {


Pizza pizza = null;

if (type.equals("cheese")) {
pizza = new CheesePizza();
} else if (type.equals("pepperoni")) {
pizza = new PepperoniPizza();
} else if (type.equals("clam")) {
pizza = new ClamPizza();
} else if (type.equals("veggie")) {
pizza = new VeggiePizza();
}
return pizza;
}
} 9
01/12/2022
SimplePizzaFactory
• Advantage: We have one place to go to add a new
pizza.

• Disadvantage: Whenever there is a change, we need


to break into this code and add a new line. (but at
least it is in one place!!)

01/12/2022 10
Rework of PizzaStore
public class PizzaStore { Store is composed
SimplePizzaFactory factory; of a factory.

public PizzaStore(SimplePizzaFactory factory) {


this.factory = factory;
}

public Pizza orderPizza(String type) {


Pizza pizza;

pizza = factory.createPizza(type); Creation of pizza is


delegated to factory.
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();

return pizza;
}
} 01/12/2022 11
Simple Factory Defined
• This is not an official pattern, but it is commonly
used.
• Not a bad place to start.
• When people think of “Factory”, they may actually be
thinking of this.

01/12/2022 12
Change Now Occurs…
• The PizzaStore is very popular and it needs to be
franchised.
– New York is interested
– Chicago is interested
– And perhaps one day Fairfax…

• Since PizzaStore is already composed of a Simple Factory,


then this should be easy! Let’s just create PizzaStore with a
different SimpleFactory.

01/12/2022 13
Example

//NY Pizza Factory has a different if/else logic


NYPizzaFactory nyFactory = new NYPizzaFactory();

//Create the Pizza Store, but use this Simple Factory


//instead
PizzaStore nyStore = new PizzaStore(nyFactory);

//Order pizza
nyStore.order(“Veggie”);

01/12/2022 14
More change happens…

New York likes the PizzaStore, but they want to add


more functionality, such as schedule a delivery.

New York attempts to extend PizzaStore…

public class NYPizzaStore extends PizzaStore {

public void ScheduleDelivery() {



}
}

01/12/2022 15
More change happens… (cont)
NYPizzaFactory nyFactory = new NYPizzaFactory();
NYPizzaStore nyStore = new NYPizzaStore(nyFactory);

//Order pizza
nyStore.order(“Veggie”);
myStore.ScheduleDelivery();

New York says the following:


– We only have one way to create pizzas; therefore, we don’t
need to use composition for the pizza creation.

– We are not happy that we have to create our extended Pizza


store and create a unique factory for creating pizzas. These
two classes have a one-to-one relationship with each other.
Can’t they be combined??
01/12/2022 16
What New York wants
A framework so that NY can do the following:
• Create pizzas in a NY style
• Add additional functionality that is applicable to NY
only.

01/12/2022 17
A Framework for Pizza Store
public abstract class PizzaStore {

abstract Pizza createPizza(String item);

public Pizza orderPizza(String type) {


Pizza pizza = createPizza(type);

pizza.prepare();
. . .
return pizza;
}
}

NOTE: We are using inheritance here to create the pizzas, not composition.
Also, the constructor for PizzaStore has been removed.

01/12/2022 18
NYPizzaStore
public class NYPizzaStore extends PizzaStore {

Pizza createPizza(String item) {


if (item.equals("cheese")) {
return new NYStyleCheesePizza();
} else if (item.equals("veggie")) {
return new NYStyleVeggiePizza();
} else if (item.equals("clam")) {
return new NYStyleClamPizza();
} else if (item.equals("pepperoni")) {
return new NYStylePepperoniPizza();
} else return null;
}

void ScheduleDelivery();
}
The subclass is defining how the pizza is created….and it is also providing
unique functionality that is applicable to New York.
01/12/2022 19
Factory Method
public abstract class PizzaStore {

abstract Pizza createPizza(String item);

public Pizza orderPizza(String type) {


Pizza pizza = createPizza(type);

pizza.prepare();
. . .
return pizza;
}
}
Factory Method simply sets up an interface for creating a Product (in this
case, a type of Pizza). Subclasses decide which specific Product to
create.
01/12/2022 20
Test Drive

1) PizzaStore nyStore = new NYPizzaStore();

2) nyStore.orderPizza("cheese");

3)Calls createPizza(“cheese”). The NYPizzaStore version of


createPizza is called. It returns a
NYStyleCheesePizza();

4) orderPizza continues to call the “parts that do not


vary”, such as prepare, bake, cut, box.

01/12/2022 21
Factory Method Defined
GoF Intent: “Defines an interface for creating an object, but
lets subclasses decide which class to instantiate. Factory
Method lets a class defer instantiation to subclasses.”

01/12/2022 22
Definitions
• Product - abstraction of the object that we need to create (Pizza)

• Concrete Product – implementations of a specific Product


(NYStyleCheesePizza)

• Creator – abstraction of the object that will create a Product


(PizzaStore). Contains factory method.

• Concrete Creator – implementation of a Creator that creates a


specific ConcreteProduct (NYPizzaStore)

01/12/2022 23
IMPORTANT

The Factory Method should just return


a ConcreteProduct.

01/12/2022 24
Lab
public abstract class PizzaStore {

abstract Pizza createPizza(String item);

public Pizza orderPizza(String type) {


Pizza pizza = createPizza(type);
. . .
return pizza;
}
}
• Did we separate out the parts that vary from the parts that do not vary?
• Did we Program to an Interface, not an Implementation?
• Does the Hollywood Principle apply here?
• Did we favor composition over inheritance?

01/12/2022 25
Parameterized Factory Method
• Another example is actually a Parameterized Factory
Method since it can make more than one object
(based on some input parameter).

abstract Pizza createPizza(String


item);

01/12/2022 26
Simple Factory Method
public abstract class PizzaStore {

abstract Pizza createPizza(); //no parameter!

public Pizza orderPizza(String type) {


Pizza pizza = createPizza(type);
. . .
}
}

public class NYPizzaStore extends PizzaStore {

Pizza createPizza() {
return new NYStylePizza(); //just one product returned
}
}

01/12/2022 27
Simple Factory Method (with Default)
public abstract class PizzaStore {

void Pizza createPizza() {


return new DefaultPizza();
}

public Pizza orderPizza(String type) {


Pizza pizza = createPizza(type);
. . .
}
}

In this example, there is default Product created (DefaultPizza).

01/12/2022 28
SimUDuck
public class MallardDuck extends Duck { MallardDuck is tied to
two specific
public MallardDuck() { implementations.
quackBehavior = new Quack();
flyBehavior = new FlyWithWings();
}

Developer would
have to know to do
this. The design
does not enforce it.

01/12/2022 29
Before
public abstract class Duck {

FlyBehavior flyBehavior;
QuackBehavior quackBehavior;

public Duck() {
}

//Not shown: setFlyBehavior, setQuackBehavior


//Not shown: abstract display method, fly, quack
}

01/12/2022 30
After
public abstract class Duck {

FlyBehavior flyBehavior;
QuackBehavior quackBehavior;
Factory Methods
abstract FlyBehavior createFly();
abstract QuackBehavior createQuack();

public Duck() {
flyBehavior = createFly();
quackBehavior = createQuack();
}
}
01/12/2022 31
Now we create MallardDuck…
public class MallardDuck extends Duck {
Note that the
public MallardDuck() { constructor is empty.
}

FlyBehavior createFly() {
return FlyWithWings();
}
Developer is “forced” to
QuackBehavior createQuack() { specify implementations of
return Quack(); Fly and Quack.
}

01/12/2022 32
Alternative Design: Default Behavior

public abstract class Duck {

FlyBehavior flyBehavior; MallardDuck does not


QuackBehavior quackBehavior; have to implement these
methods.
FlyBehavior createFly() {
return DefaultFly();
}

QuackBehavior createQuack() {
return DefaultQuack();
}

public Duck() {
flyBehavior = createFly();
quackBehavior = createQuack();
}
}
01/12/2022 33
Factory Method and Template
public abstract class CaffeineBeverage {

final void prepareRecipe() {


boilWater();
brew();
pourInCup();
Example re-worked
Condiment c = createCondiment();
here
addCondiments(c);
}

abstract void brew();

abstract Condiment createCondiment();

void addCondiments(Condiment c) {
//add condiment c
}
}
01/12/2022 34
Summary
• Pattern Name – Factory Method
• Problem – Do not want our framework to be tied to a
specific implementation of an object.
• Solution
– Let subclass decide which implementation to use (via
use of an abstract method)
– Tie the Creator with a specific Product Implementation
• Consequences
– Simple Factory Method
– Simple Factory Method with Default Behavior
– Parameterized Factory Method
– Factory and Template Together
01/12/2022 35
Changes..
• Objectville Pizza HQ gets complaints that the different
franchises are not using quality ingredients. They decide
that all Pizzas must be composed of the following
ingredients:
– Dough, Sauce, Cheese, Veggies, Pepperoni, and Clams.
• New York says those ingredients are fine, but they want to
use their own regional ingredients for all types of pizza, for
example
– Dough = Thin Crust Dough
– Sauce = Marinara
– Cheese = Reggiano
– Veggies = Garlic, Onion
01/12/2022 36
Pizza
public class Pizza {

Dough dough;
Sauce sauce;
Pizza becomes composed of
Veggies veggies[];
different ingredients.
Cheese cheese;
Pepperoni pepperoni;
Clams clam;
Question: How do we
get these ingredients
. . . associated with a
Pizza??
}

01/12/2022 37
One idea…Constructor w/many parameters

public class Pizza {

public Pizza(Dough d, Sauce s, Cheese c, Veggies v,


Pepperoni p, Clams c) {

this.dough = d;
this.sauce = s; Makes sense…whenever
this.veggies = v; you create a pizza, you
this.cheese = c; must specify these
this.pepperoni = p; ingredients…
this.clam = c;
}
}

01/12/2022 38
Rework NYPizzaStore
public class NYPizzaStore extends PizzaStore {

Pizza createPizza(String item) {

if (item.equals("cheese")) {
return new NYStyleCheesePizza(new ThinCrustDough(),
new Marinara(), new Reggiano(), null, null );

} else if (item.equals("veggie")) {
return new NYStyleVeggiaPizza(new ThinCrustDough(),
new Marinara(), new Reggiano(), mew Garlic() , null)
}
}
This will cause a lot of maintenance headaches!!! Imagine what happens
when we create a new pizza!
We know that we have a certain set of ingredients that are used for New
York..yet we have to keep repeating that set with each constructor. Can we
define this unique set just once??
39
01/12/2022
PizzaIngredientFactory
Create an interface for creating the different ingredients of Pizza.

public interface PizzaIngredientFactory {

public Dough createDough();


Note that each
public Sauce createSauce();
ingredient of Pizza
public Cheese createCheese(); has a corresponding
public Veggies[] createVeggies(); method defined in
public Pepperoni createPepperoni(); the interface.
public Clams createClam();

01/12/2022 40
NYPizzaIngredientFactory

public class NYPizzaIngredientFactory implements PizzaIngredientFactory {

public Dough createDough() {


return new ThinCrustDough(); Here we see the set
}
of ingredients that
public Sauce createSauce() { are specific to the NY
return new MarinaraSauce(); region.
}

public Cheese createCheese() {


return new ReggianoCheese();
} Note that each time a
createXXX() method is
. . . called, a new instance
}
is returned. This will
be important later on.

01/12/2022 41
CheesePizza
public class CheesePizza extends Pizza { Instead of many
ingredient parameters,
PizzaIngredientFactory ingredientFactory; we just pass one.

public CheesePizza(PizzaIngredientFactory ingredientFactory) {


this.ingredientFactory = ingredientFactory;
}

void prepare() {
dough = ingredientFactory.createDough();
Creation
sauce = ingredientFactory.createSauce();
delegated
cheese = ingredientFactory.createCheese();
}
}

Note: Not all


Does this remind you of another pattern?? ingredients have to
01/12/2022 be used! 42
NYPizzaStore (pg 152)
public class NYPizzaStore extends PizzaStore {
The specific
ingredient factory
protected Pizza createPizza(String item) {
is defined once
Pizza pizza = null;
for the NY region.
PizzaIngredientFactory ingredientFactory =
new NYPizzaIngredientFactory();

if (item.equals("cheese")) {
pizza = new CheesePizza(ingredientFactory);
} else if (item.equals("veggie")) {
pizza = new VeggiePizza(ingredientFactory);
} else if (item.equals("clam")) {
pizza = new ClamPizza(ingredientFactory);
} else if (item.equals("pepperoni")) {
pizza = new PepperoniPizza(ingredientFactory);
}
return pizza;
01/12/2022 43
Abstract Factory Defined

GoF Intent: “Provides an interface for creating families of


related or dependent objects without specifying their
concrete classes.”

01/12/2022 44
Factory Method vs. Abstract Factory
• Factory Method
– Uses inheritance to create a Concrete Product
– Sub classes decide which Concrete Product to use

• Abstract Factory
– Uses composition to create objects
– The objects created were a part of a family of objects.
For example, NY region had a specific set of ingredients.
– An abstract factory actually contains one or more
Factory Methods!
01/12/2022 45
Database Example
• Imagine you wanted to created a database manager object as an
enterprise component. This object must not be tied to a specific
database implementation.

• Each specific database uses different objects:


– Connection
– Command
– Adapter
– Data Reader

• Oracle, SQL Server, Informix, etc will have their own version of
these Sub Products.
01/12/2022 46
DatabaseFactory
public abstract class DatabaseFactory
{
public abstract IDbCommand CreateCommand();
public abstract IDbCommand CreateCommand(string cmdText);
public abstract IDbCommand CreateCommand(string cmdText, IDbConnection cn);
public abstract IDbConnection CreateConnection();
public abstract IDbConnection CreateConnection(string cnString);
public abstract IDbDataAdapter CreateDataAdapter();
public abstract IDbDataAdapter CreateDataAdapter(IDbCommand selectCmd);
public abstract IDataReader CreateDataReader(IDbCommand dbCmd);
}

Each database implementation (Oracle, SQL Server, etc) will need to create
their own version of this DatabaseFactory.

The specific DatabaseFactory must be sent to the constructor of the


framework class DatabaseManager.

01/12/2022 47
Abstract Factory and Singleton
• If you have many different Abstract Factories, you
probably just need one instance of each abstract
factory.

• You can use a Singleton to define each Abstract


Factory.

01/12/2022 48
A more interesting case…
What if NY Pizza Store wanted the flexibility to change their
ingredients all the time??

For example, one day use:


– ThickCrust Dough (not Thin)
– Marina Sauce (which was previously used)
– Provolone Cheese (not Reggiano)

And then next week the cheese needs to be changed to Cheddar


(since Provolone shipment didn’t come in time).

01/12/2022 49
What will happen??
• Class Explosion!

• We would need an Abstract Factory for every


possible combination…and when we add a new
ingredient, we could have to create even more
Abstract Factories.

01/12/2022 50
Solution: Abstract Factory and Prototype

When we create the abstract factory, pass the different


applicable products in the constructor.

PizzaIngredientFactory ingredientFactory =
new NYPizzaIngredientFactory
(new ThinCrustDough(), new MarinaraSauce(),
new Provolone() );

These products could easily come from an XML file or


even by the user during runtime.

01/12/2022 51
Solution: Abstract Factory and Prototype

• The abstract factory can then be passed to the


different types of Pizzas.
• When a method is called (ie, createDough,
createSauce), a cloned copy of the Product is
returned.
– This ensures that each call to a createXXX method
returns a unique instance.
– Note: In our standard abstract factory, a unique
instance is returned every time you call a
createXXX method.
01/12/2022 52
Abstract Factory: Last Thoughts

• This may be a hard pattern to “see” during the initial


design process.

• You may encounter this pattern during refactoring.

01/12/2022 53
Summary
• Pattern Name – Abstract Factory
• Problem – Need to way to create a family of products
• Solution
– Create an interface for creating products
• Consequences
– Objects are created using interface
– Composition is used to create objects
– Abstract Factory and Singleton
– Abstract Factory and Prototype

01/12/2022 54
Credits
Jonathan Simon
jonathan_simon@yahoo.com

You might also like