Design Pattern --- (4) Factory method Pattern , (5) Abstract Factory Pattern
===
## Under what circumstances will the factory method pattern be used?
* A class cannot anticipate the type of objects it needs to create beforehand.
For example:
I have a suepr-class Animal and a ton of sub-classes like dog,cat,duck,etc. So I want to create an animal object but I don't know which sub-classes to be instantiated before the run time. In other words,I am able to dynamically select the type at the run time.
* You want to localize the logic to instantiate a complex object.
For example:
EU and NA both have the cheese pizza,yet they taste are different,the relation diagram is :

But I can improve the complex relationships to make them more flexible:

## How does they implement in code?
As per above situation,suppose I have the Pizza interface ,which has two subclass,cheese pizza and seafood pizza.In addition,there are two pizza store selling them but the taste is different.
```java
abstract class PizzaStore
{
public abstract Pizza create(String taste);
public Pizza order(String taste)
{
//create
Pizza pizza = create(taste);
//do something
pizza.prepare();
pizza.cook();
return pizza;
}
}
class NAPizzaStore extends PizzaStore
{
public Pizza create(String taste)
{
if(taste.equals("cheese"))
return new NACheesePizza();
else if(taste.equals("seafood"))
return new NASeafoodPizza();
return null;
}
}
class EUPizzaStore extends PizzaStore
{
public Pizza create(String taste)
{
if(taste.equals("cheese"))
return new EUCheesePizza();
else if(taste.equals("seafood"))
return new EUSeafoodPizza();
return null;
}
}
Interface Pizza
{
void prepare();
Pizza cook();
}
public class client
{
public static void main(String[] arg )
{
NYPizzaStore NYPS = new NYPizzaStore();
NYPS.order("cheese");
NYPS.order("seafood");
EUPizzaStore NYPS = new EUPizzaStore();
EUPS.order("cheese");
EUPS.order("seafood");
}
}
```
---
## What is the relationship between the factory method pattern and the abstract factory pattern ?
The abstract factory pattern actually is a set of the factory methods,so an abstract factory makes use of multiple factory methods.
## Under what circumstances will the abstract factory pattern be used?
An output of a factory depends on several factories.
For example:
Creating a pizza has to add a lot of ingredients like dough,sauce,etc,and each ingredients need a factory to output.
Here is a code without using abstract factory to complete.
↓↓↓
```java=
class NAPizzaStore extends PizzaStore
{
NADoughFactory DF;
NASauceFactory SF;
NACheeseFactory CF;
NAClamFactory CLF;
public Pizza create(String taste)
{
if(taste.equals("cheese"))
return new NACheesePizza(DF,SF,CF);
else if(taste.equals("seafood"))
return new NASeafoodPizza(DF,SF,CLF);
return null;
}
}
class NACheesePizza extends Pizza
{
NADoughFactory DF;
NASauceFactory SF;
NACheeseFactory CF;
public NACheesePizza(NADoughFactory DF,NASauceFactory SF,NACheeseFactory CF)
{
this.DF =DF;
this.SF =SF;
this.CF =CF;
}
public void prepare()
{
dough = DF.create();
sauce = SF.create();
cheese = CF.create();
}
}
class EUPizzaStore extends PizzaStore
{
EUDoughFactory DF;
EUSauceFactory SF;
EUCheeseFactory CF;
EUClamFactory CLF;
public Pizza create(String taste)
{
if(taste.equals("cheese"))
return new EUCheesePizza(DF,SF,CF);
else if(taste.equals("seafood"))
return new EUSeafoodPizza(DF,SF,CLF);
return null;
}
}
```
Obviously,this code is almost unmaintainable,so the abstract factory will come into play.
## How does they implement in code?
The concept is that I build a large abstract factory to manage the above-mentionted several ingredients factories.
```java=
abstract class IngredientsFactory
{
public abstract Dough createDough();
public abstract Sauce createSauce();
public abstract Cheese createCheese();
public abstract Clam createClam();
}
class NAIngredientsFactory extends IngredientsFactory
{
public Dough createDough()
return new NADough();
public Sauce createSauce()
return new NASauce();
public Cheese createCheese()
return new NACheese;
public Clam createClam()
return new NAClam();
}
class NAPizzaStore extends PizzaStore
{
NAIngredientsFactory NAIF = new NAIngredientsFactory();
public Pizza create(String taste)
{
if(taste.equals("cheese"))
return new NACheesePizza(NAIF);
else if(taste.equals("seafood"))
return new NASeafoodPizza(NAIF);
return null;
}
}
class NACheesePizza extends Pizza
{
NAIngredientsFactory NAIF;
public CheesePizza(NAIngredientsFactory NAIF)
{
this.NAIF = NAIF;
}
public void prepare()
{
dough = NAIF.createDough();
sauce = NAIF.createSauce();
cheese = NAIF.createCheese();
}
}
class EUIngredientsFactory extends IngredientsFactory
{
public Dough createDough()
return new EUDough();
public Sauce createSauce()
return new EUSauce();
public Cheese createCheese()
return new EUCheese;
public Clam createClam()
return new EUClam();
}
class EUPizzaStore extends PizzaStore
{
EUIngredientsFactory EUIF = new EUIngredientsFactory();
public Pizza create(String taste)
{
if(taste.equals("cheese"))
return new CheesePizza(EUIF);
else if(taste.equals("seafood"))
return new SeafoodPizza(EUIF);
return null;
}
}
class EUCheesePizza extends Pizza
{
EUIngredientsFactory EUIF;
public EUCheesePizza(EUIngredientsFactory EUIF)
{
this.EUIF = EUIF;
}
public void prepare()
{
dough = EUIF.createDough();
sauce = EUIF.createSauce();
cheese = EUIF.createCheese();
}
}
public class client
{
NAPizzaStore NAPS = new NAPizzaStore();
Pizza cheesepizza = NAPS.order("cheese");
Pizza seafoodpizza = NAPS.order("seafood");
EUPizzaStore EUPS = new EUPizzaStore();
Pizza cheesspizza = EUPS.order("cheese");
Pizza seafoodpizza = EUPS.order("seafood");
}
```
## Conclusion
The factory method and abstract factory both have the same keyword "defer".The former defers the instantiation from the super-class to the sub-classes and the latter defers the implementation of a set of factories to the sub-classes.
## Reference
* Chris
https://www.youtube.com/watch?v=EcFVTgRHJLM&t=1s
https://www.youtube.com/watch?v=v-GiuMmsXj4
https://blog.techbridge.cc/2017/05/22/factory-method-and-abstract-factory/
###### tags: `Design Pattern` `Java` `教學`