Read headFirst design mode and headfirst Design Mode
Every time I write a blog, I don't know how to introduce the topic to be written. This is a headache. Today, we will go straight to the door. What we want to learn today is the factory model, where factories are the place for mass manufacturing. Here, the factory is the place where mass production objects are located.
Examples in learning books
Assume that you have a pizza store named PizzaStore and there are various types of pizza in the store. Now you need to produce pizza according to the order, and this may happen.
public Pizza orderPizza(String type) { Pizza pizza = null; if (type.equals("cheese")) pizza = new CheesePizza(); else pizza = new GreekPizza(); }
Put the required pizza directly in the orderPizza method. What about adding a new pizza ...... Let's skip this step. Let's take a look at how to use a simple factory. (The book says that a simple factory is not a "real" model, but more like a programming habit. Well, we will not be confused about it.) We need a class SimplePizzaFactory dedicated to producing pizza, the task for producing pizza is handed over to it, just like this:
/*** Factory specializing in the production of pizza */public class SimplePizzaFactory {public static Pizza createPizza (String type) {Pizza pizza = null; if (type. equals ("cheese") pizza = new CheesePizza (); else pizza = new GreekPizza (); return pizza ;}}
Now that you have obtained the desired pizza, you need to take the following steps to complete the pizza order: prepare (), bake (), cut (), boxed box (). these methods are the same for all pizza, so a pizza abstract class is required. These methods can be implemented directly in this abstract class.
Public abstract class Pizza {public void prepare () {System. out. println ("prepare"); description ();} public void bake () {System. out. println ("bake");} public void cut () {System. out. println ("cut");} public void box () {System. out. println ("box");} public abstract void description (); // description pizza}
The specific pizza (such as cheesePizza) inherits this Pizza class and adds its own description to the description method.
public class CheesePizza extends Pizza { @Override public void description() { System.out.println("default NY Cheese Pizza"); }}
I will not write anything else. Now I can use the factory to produce pizza. At this time, the orderPizza method is probably like this.
public class PizzaStore { public Pizza orderPizza(String type) { Pizza pizza = SimplePizzaFactory.createPizza(type); pizza.prepare(); pizza.bake(); pizza.cut(); pizza.box(); return pizza; }}
You may ask, isn't this just to move the question from one place to another? The problem still exists. Yes, I thought the same way at first, but it is good to think about it. If other classes also need to produce pizza? Are you still writing the code for producing pizza? The expression in the book means that customers in simple factory SimplePizzaFactory may have other things, that is, they also need to produce pizza in other classes. Therefore, it is a good choice to create a simple factory based on actual conditions.
The book divides the factory model into three categories (simple factories are also considered as one here): simple factories, factory methods, and abstract factories. Simple factories have already been introduced, then let's take a look at the factory method and abstract factory.
Factory method
Now the pizza store has a good business and is ready to open a franchise store. In New York and Chicago, there are some franchisees, including NYPizzaStore and ChicagoPizzaStore, however, because of the differences in regions, people have different tastes. That is to say, the flavors of the same pizza are different. For example, cheesePizza in New York is thicker, the cheesePizza in Chicago is thinner. In this way, simple factories cannot be used? I will not answer the question first. Next I will look at it. Since pizza has different flavors in different places, let them make their own pizza and write an abstract method to create pizza in PizzaStore.
public abstract Pizza createPizza(String type);
Then call this method in orderPizza to get the desired pizza. The original simple factory can be replaced
Pizza pizza = createPizza(type);
A specific pizza store (such as NYPizzaStore and ChiragoPizzaStore) inherits the abstract pizza store PizzaStore, and then implements the createPizza method for creating pizza, such
NYPizzaStore
// The default value is pizza @ Override public Pizza createPizza (String type) {Pizza pizza = null; if (type. equals ("cheese") pizza = new CheesePizza (); else pizza = new GreekPizza (); return pizza ;}
ChiragoPizzaStore
@Override public Pizza createPizza(String type) { Pizza pizza = null; if (type.equals("cheese")) { pizza = new ChicagoCheesePizza(); } else pizza = new ChicagoGreekPizza(); return pizza; }
You can test it.
ChicagoPizzaStore chicagoPizzaStore = new ChicagoPizzaStore(); chicagoPizzaStore.orderPizza("cheese");
As you can see, different pizza stores produce different pizza, all rely on public abstract Pizza createPizza (String type); this method can produce different pizza, just like a factory. Therefore, this method is called a factory method. The factory method returns a specific product.
Definition of factory method mode
Defines an interface for object creation, but the subclass determines which class is to be instantiated. The factory method delays the class Instantiation to the subclass.
As you can see, the two pizza stores are responsible for creating pizza, so I thought I could not give the two pizza stores the action of creating pizza to a simple factory, just like this.
Public class NoSimplePizzaFactory {// identify the region public static pizza createPizza (Class <? Extends PizzaStore> clazz, String type) {if (clazz = null) throw new NullPointerException ("address cannot be blank"); if (StringUtils. isNullOrEmpty (type) throw new NullPointerException ("type cannot be empty"); if (clazz. getSimpleName (). equals (NYPizzaStore. class. getSimpleName () {if (type. equals ("cheese") return new CheesePizza (); else return new GreekPizza ();} else if (clazz. getSimpleName (). equals (ChicagoPizzaStore. class. getSimpleName () {if (type. equals ("cheese") return new chicagcheesepizza (); else return new chicaggreekpizza ();} else return null ;}}
So you can call the pizza method in a specific pizza store to get the pizza.
NoSimplePizzaFactory.createPizza(getClass(), type);
Let's take a look at the question just now: Can I use a simple factory in the abstract class PizzaStore to create different pizza in different regions? The answer is yes, because we now have a simple factory NoSimplePizzaFactory (simple factory is not simple), which can produce different pizza in different regions. So let's use an overloaded orderPizza method or modify the original orderPizza method, just like this.
public Pizza orderPizza(Class<? extends PizzaStore> clazz, String type) { Pizza pizza = NoSimplePizzaFactory.createPizza(clazz, type); pizza.prepare(); pizza.bake(); pizza.cut(); pizza.box(); return pizza; }
In this way, different pizza regions can be created.
At present, pizza's business is getting better and better. The random problem is that the supply of pizza raw materials is in short supply, and the raw materials used by pizza in various regions may be different,
In order to solve the problem that the supply of raw materials is in short supply and the raw materials used in pizza vary from region to region, we can build a raw material factory in each region. To supply the raw materials required by the pizza store in the region. Create an abstract raw material factory, PizzaIngredientFactory, which contains raw material manufacturing methods, such:
Dough createDough(); Sauce createSauce();
This factory is an interface, and then two specific raw material factories ChicagoPizzaIngredientFactory and NYPizaaIngredientFactory implement it. Different factories make different raw materials,
ChicagoPizzaIngredientFactory
@Override public Dough createDough() { return new ChicagoDough(); } @Override public Sauce createSauce() { return new ChicagoSauce(); }
NYPizaaIngredientFactory
@Override public Dough createDough() { return new NYDough(); } @Override public Sauce createSauce() { return new NYSauce(); }
Add the raw materials to pizza, that is, add the raw material attributes to the Pizza class.
Dough dough; // Dough Sauce; // sauce
You can also add other raw material properties by yourself. These raw materials are produced by the factory, so the factory is also placed in the Pizza class.
private PizzaIngredientFactory ingredientFactory; public Pizza(PizzaIngredientFactory ingredientFactory) { this.ingredientFactory = ingredientFactory; }
Then add the corresponding constructor in the specific pizza, and then produce the raw materials in the preparation of prepare, So modify the prepare method.
public void prepare() { System.out.println("prepare"); description(); if (ingredientFactory != null) { dough = ingredientFactory.createDough(); sauce = ingredientFactory.createSauce(); System.out.println(dough.getName()); System.out.println(sauce.getName()); } }
Then you can use the raw material factory in the simple factory NoSimplePizzaFactory, and then introduce the raw material factory in this class.
private static PizzaIngredientFactory chicagoPizzaIngredientFactory = new ChicagoPizzaIngredientFactory(); private static PizzaIngredientFactory nyPizaaIngredientFactory = new NYPizaaIngredientFactory();
Create pizza as an injection factory and modify it.
if (clazz.getSimpleName().equals(NYPizzaStore.class.getSimpleName())) { if (type.equals("cheese")) return new CheesePizza(); else return new GreekPizza(nyPizaaIngredientFactory);
Test it and you will find that different pizza can be obtained through the factory. This example only describes the factory model, so there are still some shortcomings. For example, once the pizza region and type are determined, the pizza obtained through orderPizza is determined, I cannot dynamically change the raw materials used to create pizza. My idea is that as long as the raw material factory is controlled, the raw materials can be dynamically changed during pizza production.
In this example, we can see that the pizza raw material factory is an abstract factory.
Abstract Factory model definition
Provides an interface for creating families of related or dependent objects without specifying specific classes.
Is the factory method lurking in the abstract factory?
We can see that the PizzaIngredientFactory interface has two abstract methods for manufacturing raw materials. These two methods are used to produce raw materials, so these two are factory methods.
Summary
Simple factory dedicated object Creation
The factory method is an abstract method of a production product. The specific product to be produced is determined by the specific subclass.
Abstract Factory is used to create a "family" of products. A specific product family is determined by a specific factory. Abstract Factory methods are usually factory methods.