- π About the author: Hello, I'm cabbage ~ ~, a sophomore in school, and a new star creator in the Java field.
- π Personal homepage: Cabbage CSDN blog
- π Series column: This article is written in the Java design pattern column: Isn't that the Java design pattern
- π§ If there are mistakes in the knowledge points of the article, please correct them! Learn and make progress with you π
- π₯ If you feel the blogger's article is good, please π Three company support π Check out the blogger
preface
Today, I learned the factory pattern in Java design pattern and sorted out the teacher's notes; The class diagram in the article (I drew it lazily) can be used for your reference to the relationship between classes. I hope you like it.
1, Using traditional methods
Class diagram
Step summary
Step 1: create a Pizza abstract class
public abstract class Pizza { public String name; public abstract void prepare(); public void bake() { System.out.println(name + " baking"); } public void cut() { System.out.println(name + " cutting"); } public void box() { System.out.println(name + " boxing"); } public void setName(String name) { this.name = name; } }
Analysis: this class is used to represent the whole process of making pizza: prepare(), bake(), cut() and box(). Assuming that the materials required in each pizza preparation stage are different, the preparation stage is defined as an abstract method, and the other three stages are the same.
Step 2: create two pizza classes
public class CheesePizza extends Pizza{ @Override public void prepare() { System.out.println("Cheese pizza is being prepared"); } }
Analysis: this class represents cheese pizza. Simply rewrite the preparation stage
public class BeefPizza extends Pizza{ @Override public void prepare() { System.out.println("Beef pizza is being prepared"); } }
Analysis: this class represents beef pizza. It's also a simple rewrite of the preparation stage
Step 3: make an order for pizza
public class OrderPizza { public OrderPizza() { Pizza pizza = null; do { String pizzaType = getType(); if ("cheese".equalsIgnoreCase(pizzaType)) { pizza = new CheesePizza(); pizza.setName("cheese"); } else if ("beef".equalsIgnoreCase(pizzaType)) { pizza = new BeefPizza(); pizza.setName("beef"); } else { break; } pizza.prepare(); pizza.bake(); pizza.cut(); pizza.box(); } while (true); } // Write a method to get the type of pizza you want to order private String getType() { try { BufferedReader strin = new BufferedReader(new InputStreamReader(System.in)); System.out.println("input pizza type:"); String str = strin.readLine(); return str; } catch (IOException e) { e.printStackTrace(); return ""; } } }
Analysis: looking at the code slowly, you can see that the logic code for ordering pizza is written in the constructor of this class, and the getType() method is used to obtain the type of pizza you want to order. However, if we need to add new pizza, we need to continue to add corresponding logical statements from this class, so as to modify the pizza ordering class, which violates the OCP principle
Step 4: create a run class
public class PizzaStore { public static void main(String[] args) { new OrderPizza(); } }
Operation results:
Analysis of advantages and disadvantages
- Advantages: easy to understand, simple and easy to operate
- Disadvantages: it violates the ocp principle of design pattern, that is, it is open to extension and closed to modification. That is, when we add new functions to the class, we try not to modify the code or modify the code as little as possible
2, Use simple factory
Class diagram
Basic introduction
- The simple factory mode belongs to the creation mode, which is a kind of factory mode. The simple factory pattern is a factory object that determines which product class instance to create. The simple factory pattern is the simplest and most practical pattern in the factory pattern family
- The simple factory pattern defines a class for creating objects, which encapsulates the behavior (code) of instantiating objects
- In software development, when we will use a lot of to create a, a class or a batch of objects, we will use the factory pattern
Step summary
Step 1: create a simple factory
public class SimpleFactory { public static Pizza createPizza2(String orderType) { Pizza pizza = null; if ("beef".equalsIgnoreCase(orderType)) { pizza = new BeefPizza(); pizza.setName(" beef "); } else if ("cheese".equalsIgnoreCase(orderType)) { pizza = new CheesePizza(); pizza.setName("cheese"); } return pizza; } }
Analysis: a simple factory is also called a static factory. We write a static method to facilitate the call of the following code. The classes used here are the same as those used by traditional methods, and have not changed
Step 2: make an order for pizza
public class OrderPizza2 { public OrderPizza2() { do { String orderType = getType(); Pizza pizza = SimpleFactory.createPizza2(orderType); if (pizza != null) { pizza.prepare(); pizza.bake(); pizza.cut(); pizza.box(); } else { System.out.println(" Failed to order pizza "); break; } } while (true); } private String getType() { try { BufferedReader strin = new BufferedReader(new InputStreamReader(System.in)); System.out.println("input pizza type:"); String str = strin.readLine(); return str; } catch (IOException e) { e.printStackTrace(); return ""; } } }
Analysis: the constructor of this class uses the simple factory class SimpleFactory, so we don't need to write the code to add new pizza in the behavior of ordering pizza, but write the code to add new pizza from the factory, so we don't need to change this class.
Operation results:
Advantage analysis
- Using simple factory mode to create objects is more convenient and flexible, and there is no need to modify the logic of ordering pizza
3, Using factory methods
New requirements
When ordering pizza, customers can order pizza with different flavors, such as cheese pizza in Beijing, pepper pizza in Beijing, cheese pizza in London and pepper pizza in London
Class diagram
Basic introduction
- Factory method pattern design scheme: abstract the instantiation function of pizza project into abstract methods and implement them in different taste ordering subclasses.
- Factory method pattern: defines an abstract method to create an object, and the subclass determines the class to be instantiated. The factory method pattern defers instantiation of objects to subclasses.
Step summary
Step 1: create four pizza classes
public class BJCheesePizza extends Pizza { @Override public void prepare() { setName("Beijing cheese pizza"); System.out.println("Beijing cheese pizza Prepare raw materials"); } }
Analysis: the Pizza class is the same as the code above. I didn't write it again. This class is used to create cheese flavored Pizza in Beijing
public class BJPepperPizza extends Pizza{ @Override public void prepare() { setName("Pepper in Beijing pizza"); System.out.println("Pepper in Beijing pizza Prepare raw materials"); } }
Analysis: this class is used to create chili pizza in Beijing
public class LDCheesePizza extends Pizza { @Override public void prepare() { setName("London cheese pizza"); System.out.println("London cheese pizza Prepare raw materials"); } }
Analysis: this class is used to create cheese flavored pizza in London
public class LDPepperPizza extends Pizza { @Override public void prepare() { setName("Pepper in London pizza"); System.out.println("Pepper in London pizza Prepare raw materials"); } }
Analysis: this class is used to create chili pizza in London
Step 2: create an abstract class for ordering pizza
public abstract class OrderPizza { abstract Pizza createPizza(String orderType); public OrderPizza() { do { String orderType = getType(); Pizza pizza = createPizza(orderType); //Abstract method, which is completed by the factory subclass if (pizza == null){ System.out.println("Failed to order pizza"); break; } pizza.prepare(); pizza.bake(); pizza.cut(); pizza.box(); } while (true); } private String getType() { try { BufferedReader strin = new BufferedReader(new InputStreamReader(System.in)); System.out.println("input pizza type:"); String str = strin.readLine(); return str; } catch (IOException e) { e.printStackTrace(); return ""; } } }
Analysis: an abstract method createPizza() is defined in this class, which allows each factory subclass to implement itself, and the code logic for ordering pizza is written in the constructor; The getType() method is no different from the original one.
public class BJOrderPizza extends OrderPizza { @Override Pizza createPizza(String orderType) { Pizza pizza = null; if(orderType.equals("cheese")) { pizza = new BJCheesePizza(); } else if (orderType.equals("pepper")) { pizza = new BJPepperPizza(); } return pizza; } }
Analysis: this class is used to inherit the OrderPizza class and become a pizza ordering distributor in Beijing
public class LDOrderPizza extends OrderPizza { @Override Pizza createPizza(String orderType) { Pizza pizza = null; if(orderType.equals("cheese")) { pizza = new LDCheesePizza(); } else if (orderType.equals("pepper")) { pizza = new LDPepperPizza(); } return pizza; } }
Analysis: this class is also used to inherit the OrderPizza class and become a pizza ordering distributor in London
Step 3: create a run class
public class PizzaStore { public static void main(String[] args) { String loc = "beijing"; if (loc.equals("beijing")) { new BJOrderPizza(); } else { new LDOrderPizza(); } } }
Analysis: suppose you buy pizza in Beijing
Operation results:
4, Use abstract factory
Class diagram
Basic introduction
- The abstract factory pattern defines an interface for creating clusters of related or dependent objects without specifying specific classes
- Abstract factory pattern can integrate simple factory pattern and factory method pattern
- From the design level, the abstract factory pattern is an improvement (or further abstraction) of the simple factory pattern
- The factory is abstracted into two layers, absfactory (Abstract Factory) and the factory subclass of concrete implementation. Programmers can use the corresponding factory subclasses according to the type of object they create. This turns a single simple factory class into a factory cluster, which is more conducive to code maintenance and expansion.
Step summary
Step 1: create a general factory interface
public interface AbsFactory { public Pizza createPizza(String orderType); }
Analysis: this class is used to implement the following factory subclasses
Step 2: create a labor division factory
public class BJFactory implements AbsFactory { @Override public Pizza createPizza(String orderType) { Pizza pizza = null; if(orderType.equals("cheese")) { pizza = new BJCheesePizza(); } else if (orderType.equals("pepper")){ pizza = new BJPepperPizza(); } return pizza; } }
Analysis: This is a factory subclass, which is used to make pizza in Beijing
public class LDFactory implements AbsFactory { @Override public Pizza createPizza(String orderType) { Pizza pizza = null; if (orderType.equals("cheese")) { pizza = new LDCheesePizza(); } else if (orderType.equals("pepper")) { pizza = new LDPepperPizza(); } return pizza; } }
Analysis: This is a factory subclass used to make pizza in London
Step 3: create a subscription class
public class OrderPizza { private AbsFactory factory; public OrderPizza(AbsFactory factory) { setFactory(factory); } private void setFactory(AbsFactory factory) { do { this.factory = factory; String orderType = getType(); // Factory may be a factory subclass in Beijing or a factory subclass in London Pizza pizza = factory.createPizza(orderType); if (pizza == null) { System.out.println("Subscription failed"); break; } pizza.prepare(); pizza.bake(); pizza.cut(); pizza.box(); } while (true); } private String getType() { try { BufferedReader strin = new BufferedReader(new InputStreamReader(System.in)); System.out.println("input pizza type:"); String str = strin.readLine(); return str; } catch (IOException e) { e.printStackTrace(); return ""; } } }
Analysis: Pizza pizza = factory createPizza(orderType); This statement mainly uses the polymorphism in the java foundation, and the specific implementation functions are handed over to the subclass that implements its interface
Step 4: create a run class
public class PizzaStore { public static void main(String[] args) { new OrderPizza(new LDFactory()); } }
Analysis: suppose you buy pizza in London
Operation results:
summary
1. Significance of factory mode:
The code of the instantiated object is extracted and put into a class for unified management and maintenance, so as to decouple the dependency relationship with the main project. So as to improve the expansibility and maintainability of the project.
2. Three factory patterns (simple factory pattern, factory method pattern and abstract factory pattern)
3. Dependency abstraction principle of design pattern
When creating an object instance, do not directly the new class, but put the action of the new class in a factory method and return
Do not let classes inherit concrete classes, but inherit abstract classes or implement interfaces
Do not override methods already implemented in the base class.