KEMBAR78
04 - Factory Patterns - Abstarct Factory Pattern | PDF | Class (Computer Programming) | Method (Computer Programming)
0% found this document useful (0 votes)
8 views29 pages

04 - Factory Patterns - Abstarct Factory Pattern

The document discusses the Factory Method and Abstract Factory design patterns, emphasizing the importance of encapsulating object creation to enhance code flexibility and maintainability. It illustrates the application of these patterns in a pizza store scenario, where different types of pizzas are created using ingredient factories tailored to specific regions. The document also highlights the advantages and liabilities of using these design patterns in object-oriented programming.

Uploaded by

Batuhan Ekinci
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
8 views29 pages

04 - Factory Patterns - Abstarct Factory Pattern

The document discusses the Factory Method and Abstract Factory design patterns, emphasizing the importance of encapsulating object creation to enhance code flexibility and maintainability. It illustrates the application of these patterns in a pizza store scenario, where different types of pizzas are created using ingredient factories tailored to specific regions. The document also highlights the advantages and liabilities of using these design patterns in object-oriented programming.

Uploaded by

Batuhan Ekinci
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 29

previously on…

factory
PATTERNS
Meet the Factory Method Pattern
The Creator classes
! All factory patterns
encapsulate object creation

The Product classes

2
Another perspective: palallel class hierarchies
 Encapsulating knowledge into
each creator.

3
Factory Method Pattern defined

4
Master and Grasshopper
Master: Grasshopper; tell me how your training is going?
Student: Master; I have taken my study of "encapsulate what varies" further.
Master: Go on...
Student: I have learned that one can encapsulate the code that creates objects. When you have code that instantiates concrete
classes, this is an area of frequent change. I’ve learned a technique called "factories" that allows you to encapsulate this behavior
of instantiation.
Master: And these "factories, "of what benefit are they?
Student: There are many. By placing all my creation code in one object or method, I avoid duplication in my code and provide one
place to perform maintenance. That also means clients depend only upon interfaces rather than the concrete classes required to
instantiate objects. As I have learned in my studies, this allows me to program to an interface, not an implementation, and that
makes my code more flexible and extensible in the future.
Master: Yes Grasshopper, your 00 instincts are growing. Do you have any questions for your master today?
Student: Master; I know that by encapsulating object creation I am coding to abstractions and decoupling my client code from
actual implementations. But my factory code must still use concrete classes to instantiate real objects.
Master: Grasshopper; object creation is a reality of life; we must create objects or we will never create a single Java program.
But, with knowledge of this realty, we can design our code so that we have corralled this creation. Once corralled, we can protect
and care for the creation code.
Student: Master, I see the truth in this.
Master: As I knew you would. Now, please go and meditate on object dependencies.
5
public class DependentPizzaStore {
public Pizza createPizza(String style, String type) {
Pizza pizza = null;
A very dependent PizzaStore
if (style.equals("NY")) {
if (type.equals("cheese")) {
pizza = new NYStyleCheesePizza();
} else if (type.equals("veggie")) {  Let's pretend you've never heard of an
pizza = new NYStyleVeggiePizza();
} else if (type.equals("clam")) { OO factory.
pizza = new NYStyleClamPizza();
} else if (type.equals("pepperoni")) {  Here's a version of the PizzaStore that
pizza = new NYStylePepperoniPizza();
} doesn't use a factory.
} else if (style.equals("Chicago")) {
if (type.equals("cheese")) {  Make a count of the number of concrete
pizza = new ChicagoStyleCheesePizza();
} else if (type.equals("veggie")) { pizza objects this class is dependent
pizza = new ChicagoStyleVeggiePizza();
} else if (type.equals("clam")) { on.
pizza = new ChicagoStyleClamPizza();
} else if (type.equals("pepperoni")) {  If you added California style pizzas to
pizza = new ChicagoStylePepperoniPizza();
} this PizzaStore, how many objects
} else {
System.out.println("Error: invalid type of pizza"); would it be dependent on then?
return null;
}
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box(); 8
_______#_ 12
and _______#_ with California
return pizza;
}
}

6
Looking at object dependencies
 When you instantiate an
object, you are depending on
its concrete class.
 Take a look at our very
dependent PizzaStore one
slide back
 It creates all pizzas without
delegating to a factory.

 Let's look at its diagram –>

7
The Dependency Inversion Principle
 At first, it sounds like
"Program to an interface, not
an implementation", right?
 They are similar, but this one
is stronger.
 It suggests that our high-level
components should not
depend on our low-level
components; rather they
should both depend on
abstractions. Let's think about how we'd apply this
principle to our Very Dependent
PizzaStore implementation…

8
Applying the Principle
After applying the Factory Method, our diagram looks like this:

Well, it was like this before, remember?

9
Where's the "inversion" in the principle?
 It actually inverts your thinking about your OO
design.
 Look back to diagram once more and notice
that the low-level components now depend on
a higher-level abstraction.
 Likewise, the high-level component is also tied
to the same abstraction.

Let's also walk through the thinking behind the typical design process and see
how introducing the principle can invert the way you think about the design.

10
Inverting your thinking…
Now let's invert your thinking… instead of starting at
the top, start at the Pizzas and think about what you
can abstract.
Right, you start at top and Right! You're thinking about the abstraction Pizza. So
Ok, so you need to implement a
follow things down to the now, go back and think about the design of the Pizza
PizzaStore. What's the first
concrete class. But, as you've Store again.
thought that pops into your
seen, you don't want your
head?
store to know about the
concrete classes!

Close. But to do that you'll have to rely on a factory to get those concrete classes out of your
Pizza Store. Once you've done that, your different concrete pizza types depend only on an
abstraction and so does your store. We've taken a design where the store depended on concrete
classes and inverted those dependencies (along with your thinking).

11
A few guidelines to help you follow the Principle…
The following guidelines can help you
avoid OO designs that violate the
Dependency Inversion Principle

• No variable should hold a reference to a


concrete class.

• No class should derive from a concrete


class.

• No method should override an


implemented method of any of its base
classes

12
Meanwhile, back at the Pizza Store _ fresh, quality ingredient standards
We've got to do something to
ensure high quality pizzas not
to hurt Objectville brand!

Ensuring consistency with ingredients


We will build a factory that produces pizzas and ship them to our franchises!
However, franchises are located in different regions and what is red sauce in NY is not red
sauce in Chicago. So, we have different sets of ingredients to be shipped to each region.

13
Families of ingredients…
 New York uses one set of ingredients and
Chicago another. Given the popularity of
ObJectville Pizza it won't be long before you
also need to ship another set of regional
ingredients to California, and what's next?
Seattle?

 For this to work, we are going to have to


figure out how to handle families of
ingredients.

14
Building the ingredient factories
 Now we're going to build a factory to create our ingredients;
 the factory will be responsible for creating each ingredient in the ingredient family.
 the factory will need to create dough, sauce, cheese, and so on...
Here's what we're going to do:
public interface PizzaIngredientFactory { 1. Build a factory for each region.
public Dough createDough(); To do this, we'll create a subclass of
public Sauce createSauce(); PizzaIngredientFactory that implements
public Cheese createCheese(); each create method.
public Veggies[] createVeggies(); 2. Implement a set of ingredient classes to be
public Pepperoni createPepperoni(); used with the factory, like ReggianoCheese,
public Clams createClam(); RedPeppers, and ThickCrustDough. These
} classes can be shared among regions where
appropriate.
3. Then we still need to hook all this up by
working our new ingredient factories into
our old PizzaStore code.

15
Building New York ingredient factory
public class NYPizzaIngredientFactory implements PizzaIngredientFactory {
public Dough createDough() {
return new ThinCrustDough();  Specialization of NY ingredient
}
public Sauce createSauce() { factory is
}
return new MarinaraSauce();
 Marinara sauce
public Cheese createCheese() {  Reggiano Cheese
return new ReggianoCheese();
}  Fresh Clams etc.
public Veggies[] createVeggies() {
Veggies veggies[] = { new Garlic(), new Onion(), new Mushroom(), new RedPepper() };
return veggies;
}
public Pepperoni createPepperoni() {
return new SlicedPepperoni();
}
public Clams createClam() {
return new FreshClams();
}
}

16
public abstract class Pizza {
String name;
Dough dough; Reworking the pizzas…
Sauce sauce;
Veggies veggies[];  We've got our factories all fired
Cheese cheese;
Pepperoni pepperoni; up and ready to produce quality
Clams clam;
ingredients.
abstract void prepare();  Now, we just need to rework our
void bake() { Pizzas so they only use factory-
System.out.println(“Bake for 25 minutes at 350”); produced ingredients.
}
void cut() {  We'll start with our abstract
}
System.out.println(“Cutting the pizza into diagonal slices”);
Pizza class:
void box() {
System.out.println(“Place pizza in official PizzaStore box”);
}
void setName(String name) {
this.name = name;
}
String getName() {
return name;
}
public String toString() { // code to print pizza here }
}
17
Reworking the pizzas, continued…
 Now that we've got an abstract Pizza to work
from, it's time to create the New York and
Chicago style Pizzas
 only this time around they will get their public class CheesePizza extends Pizza {
ingredients straight from the factory. PizzaIngredientFactory ingredientFactory;
The franchisees' days of skimping on public CheesePizza(PizzaIngredientFactory ingredientFactory)
ingredients are over! this.ingredientFactory = ingredientFactory;
 When we wrote the Factory Method code, we }
had a NYCheesePizza and a void prepare() {
ChicagoCheesePizza class. If you look at the System.out.println(“Preparing “ + name);
two classes, the only thing that differs is the dough = ingredientFactory.createDough();
use of regional ingredients. The pizzas are sauce = ingredientFactory.createSauce();
made just the same (dough + sauce + cheese). cheese = ingredientFactory.createCheese();
The same goes for the other pizzas: Veggie, }
Clam, and so on. They all follow the same }
preparation steps; they just have different
ingredients. So, what you'll see is that we
really don't need two classes for each pizza;
the ingredient factory is going to handle the
regional differences for us.
18
Let's check out ClamPizza as well
public class ClamPizza extends Pizza {
PizzaIngredientFactory ingredientFactory;
public ClamPizza(PizzaIngredientFactory ingredientFactory) {
this.ingredientFactory = ingredientFactory;
}
void prepare() {
System.out.println(“Preparing “ + name);
dough = ingredientFactory.createDough();
sauce = ingredientFactory.createSauce();
cheese = ingredientFactory.createCheese();
clam = ingredientFactory.createClam();
}
}

19
public class NYPizzaStore extends PizzaStore { Revisiting
protected Pizza createPizza(String item) {
Pizza pizza = null;
our pizza stores
PizzaIngredientFactory ingredientFactory =
new NYPizzaIngredientFactory();
if (item.equals(“cheese”)) {
pizza = new CheesePizza(ingredientFactory);
pizza.setName(“New York Style Cheese Pizza”);
} else if (item.equals(“veggie”)) {
pizza = new VeggiePizza(ingredientFactory);
pizza.setName(“New York Style Veggie Pizza”);
} else if (item.equals(“clam”)) {
pizza = new ClamPizza(ingredientFactory);
pizza.setName(“New York Style Clam Pizza”);
} else if (item.equals(“pepperoni”)) {
pizza = new PepperoniPizza(ingredientFactory);
pizza.setName(“New York Style Pepperoni Pizza”);
}
return pizza;
}
}
20
What have we done? An Abstract Factory provides an interface
for a family of products. What's a family?
In our case it's all the things we need to
We provided a means of creating a make a pizza: dough, sauce, cheese, meats
and veggies.
family of ingredients for pizzas by
introducing a new type of factory
called an Abstract Factory.
An Abstract Factory gives us an interface for
creating a family of products. By writing
code that uses this interface, we decouple
our code from the actual factory that
creates the products. That allows us to
implement a variety of factories that From the abstract factory, we derive one
or more concrete factories that produce
produce products meant for different the same products, but with different
contexts - such as different regions, implementations.

different operating systems, or different


look and feels.
Because our code is decoupled from the We then write our code so that it uses
actual products, we can substitute different the factory to create products. By
factories to get different behaviors (like passing a variety of factories, we get a
variety of implementations of those
getting marinara instead of plum tomatoes). products. But our client code stays the
same.

21
More pizza for Ethan and Joel…
The first part of the order hasn't changed.
1. First we need a NY PizzaStore:
PizzaStore nyPizzaStore = new NYPizzaStore();

2. Now that we have a store, we can take an order:


nyPizzaStore.orderPizza(″cheese″);

3. The orderPizza() method first calls the createPizza():


Pizza pizza = createPizza(″cheese″);

22
From here things change, we use an ingredient factory
4. When the createPizza() method is called, that's
when our ingredient factory gets involved:
Pizza pizza = new CheesePizza(nyIngredientFactory);

5. Next we need to prepare the pizza. Once the


prepare() method is called, the factory is asked
to prepare ingredients.
void prepare() {
dough = factory.createDough();
sauce = factory.createSauce();
cheese = factory.createCheese();
}
6. Finally we have the prepared pizza in hand and the
orderPizza() method bakes, cuts, and boxes the pizza.

23
Abstract Factory Pattern defined

24
Consequences
 Advantages
 It isolates concrete classes.
 It makes exchanging product families easy.
 It promotes consistency among products.
 Liabilities
 Supporting new kinds of products is difficult.

25
in terms of
our PizzaStore

Is Factory Method lurking


inside the Abstract Factory?
Good catch! Yes, often the methods of an Abstract Factory are
implemented as factory methods. It makes sense, right? The
job of an Abstract Factory is to define an interface for creating
a set of products. Each method in that interface is responsible
for creating a concrete product, and we implement a subclass
of the Abstract Factory to supply those implementations. So,
factory methods are a natural way to implement your product
methods in your abstract factories.

26
Factory Method Pattern vs Abstract Factory Pattern
Factory Method Pattern Abstrat Factory Pattern
Creates objects using inheritance. Creates objects using composition.
In Factory Method pattern, you’re using a subclass to do your creation In Abstract Factory pattern, a class delegates the responsibility of
for you. In that way, clients only need to know the abstract type they object instantiation to another object via composition
are using, the subclass worries about the concrete type.
It creates only one products It groups and creates a set of related products.

27
Factory Method & Abstract Factory compared

28
Tools for your Design Toolbox
Bullet Points
• All factories encapsulate object creation.
• Simple Factory, while not a design pattern, is a simple way to
decouple your clients from concrete classes.
• Factory Method relies on inheritance: object creation is
delegated to subclasses which implement the factory method to
create objects.
• Abstract Factory relies on object composition: object creation is
implemented in methods exposed in the factory interface.
• All factory patterns promote loose coupling by reducing the
dependency of your application on concrete classes.
• The Dependency Inversion Principle guides us to avoid
dependencies on concrete types and to strive for abstractions.
• Factories are a powerful technique for coding to abstractions,
not concrete classes.

29

You might also like