Simple factory
Introduction: the simplest factory mode is not part of the standard design mode, but it is very in line with people's programming habits. All products are produced by simple factories
advantage:
- The factory class contains the necessary logical judgment to decide when to create an instance of which product. The client can avoid the responsibility of directly creating product objects and easily create corresponding products. The responsibilities of the factory and products are clearly distinguished
- The client does not need to know the class name of the specific product created, but only needs to know the parameters
- You can also import a configuration file to replace and add new specific product classes without modifying the client code
Disadvantages:
- The factory class of simple factory mode is single, which is responsible for the creation of all products. The responsibility is too heavy. Once it is abnormal, the whole system will be affected. Moreover, the factory class code will be very bloated and violate the principle of high aggregation
- It is difficult to expand the system. Once new products are added, the factory logic has to be modified, which violates the opening and closing principle
Application scenario
For the case of relatively few product types, consider using the simple factory mode. The client using the simple factory mode only needs to pass in the parameters of the factory class and does not need to care about the logic of how to create objects. It can easily create the required products.
Structure and implementation of pattern
The main roles of the simple factory model are as follows:
- Simple factory: it is the core of the simple factory pattern and is responsible for implementing the internal logic of creating all instances. The method of creating product class of factory class can be directly called by the outside world to create the required product object.
- Abstract Product: it is the parent class of all objects created by a simple factory and is responsible for describing the common interface shared by all instances.
- Concrete product: it is the creation target of simple factory mode.
UML class diagram
Concrete implementation
interface Coffee { void getName(); } class AmericanCoffee implements Coffee { @Override public void getName() { System.out.println(AmericanCoffee.class); } } class LetterCoffee implements Coffee { @Override public void getName() { System.out.println(LetterCoffee.class); } } class SimpleFactory { public static Coffee getInstance(String className) { if ("AmericanCoffee".equals(className)) { return new AmericanCoffee(); } else if ("LetterCoffee".equals(className)) { return new LetterCoffee(); } return null; } } public class Demo { public static void main(String[] args) { Coffee letterCoffee = SimpleFactory.getInstance("LetterCoffee"); if (letterCoffee != null) { letterCoffee.getName(); } } }
Factory method
Introduction: the simple factory mode violates the opening and closing principle, and the "factory method mode" is a further abstraction of the simple factory mode, that is, the factory is also interfaced. Its advantage is that the system can introduce new products without modifying the original code, that is, meet the opening and closing principle. One factory produces one product
advantage:
- Users only need to know the name of the specific factory to get the desired product, without knowing the specific creation process of the product.
- Flexibility is enhanced. For the creation of new products, you only need to write one more corresponding factory class.
- Typical decoupling framework. The high-level module only needs to know the abstract class of the product, does not need to care about other implementation classes, and meets the Demeter rule, dependency inversion principle and Richter substitution principle.
Disadvantages:
- The complexity increases and there are too many classes in the system
- It increases the abstraction and understanding difficulty of the system
- Factories can only produce one product, which can be solved by using the abstract factory pattern.
Application scenario:
- The customer only knows the name of the factory that created the product, but does not know the specific product name.
- The task of creating objects is completed by one of multiple concrete sub factories, while the abstract factory only provides the interface to create products.
- Customers don't care about the details of creating products, they only care about the brand of products
Pattern structure
The main roles of the factory method pattern are as follows.
- Abstract Factory: it provides an interface for creating products, through which the caller accesses the factory method newProduct() of a specific factory to create products.
- Concrete factory: it mainly implements the abstract methods in the abstract factory and completes the creation of specific products.
- Abstract Product: it defines the specification of the Product and describes the main characteristics and functions of the Product.
- Concrete product: it implements the interface defined by the abstract product role, which is created by the specific factory and corresponds to the specific factory one by one.
UML class diagram:
realization:
interface Coffee { void getName(); } class AmericanCoffee implements Coffee { @Override public void getName() { System.out.println(AmericanCoffee.class); } } class LetterCoffee implements Coffee { @Override public void getName() { System.out.println(LetterCoffee.class); } } interface AbstractFactory { Coffee getInstance(); } class AmericanCoffeeFactory implements AbstractFactory { @Override public Coffee getInstance() { return new AmericanCoffee(); } } class LetterCoffeeFactory implements AbstractFactory { @Override public Coffee getInstance() { return new LetterCoffee(); } } public class Demo { public static void main(String[] args) { AbstractFactory abstractFactory = new AmericanCoffeeFactory(); Coffee instance = abstractFactory.getInstance(); instance.getName(); AbstractFactory factory = new LetterCoffeeFactory(); Coffee coffee = factory.getInstance(); coffee.getName(); } }
Abstract factory
Introduction: in the factory method, a single factory can only produce a single product. But in real life, many factories are comprehensive factories, which can usually produce a variety of products
Abstract factory mode is an upgraded version of factory method mode. Factory method mode only produces products of different races and the same grade (coffee can be produced, and coffee of multiple brands, but hamburger can not be produced), while abstract factory mode can produce products of multiple grades.
advantage:
In addition to the advantages of the factory method pattern, the abstract factory pattern has the following main advantages.
- The multi-level products associated in the product family can be managed together within the class, instead of introducing multiple new classes for management.
- When the same product family is needed, the abstract factory can ensure that the client always uses only the product group of the same product.
- Abstract factory enhances the scalability of the program. When adding a new product family, there is no need to modify the original code to meet the opening and closing principle.
Disadvantages:
When a new product level needs to be added, all factory classes need to be modified. It increases the abstraction and understanding difficulty of the system.
Application scenario:
- There are multiple product families in the system. Each specific factory creates products of the same family but belonging to different hierarchical structures (note)
- The system can only consume one family of products at a time, that is, the products of the same family can be used together.
Mode structure:
The main roles of the abstract factory pattern are as follows.
- Abstract Factory: it provides an interface for creating products. It contains multiple methods for creating products newProduct(), which can create multiple products of different levels.
- Concrete Factory: it mainly implements multiple abstract methods in the abstract factory to complete the creation of specific products.
- Abstract Product: it defines the Product specification and describes the main features and functions of the Product. The abstract factory pattern has multiple Abstract products.
- Concrete product: it implements the interface defined by the abstract product role and is created by the concrete factory. It has a many-to-one relationship with the concrete factory.
UML class diagram:
**If you want to add a new product family (such as BKCCoffee and BKCHamburg), you only need to add a new factory (BKCFactory)**
But if we want to add a new product level (such as cookie), it will be a big trouble. We must modify all factories
realization:
interface Coffee { void getName(); } class McDonalCoffee implements Coffee { @Override public void getName() { System.out.println(McDonalCoffee.class); } } class KFCCoffee implements Coffee { @Override public void getName() { System.out.println(KFCCoffee.class); } } class WallaceCoffee implements Coffee { @Override public void getName() { System.out.println(WallaceCoffee.class); } } interface Hamburg { void getName(); } class McDonalHamburg implements Hamburg { @Override public void getName() { System.out.println(McDonalHamburg.class); } } class KFCHamburg implements Hamburg { @Override public void getName() { System.out.println(KFCHamburg.class); } } class WallaceHamburg implements Hamburg { @Override public void getName() { System.out.println(WallaceHamburg.class); } } interface AbstractFactory { Coffee getCoffee(); Hamburg getHamburg(); } class McDonaldFactory implements AbstractFactory { @Override public Coffee getCoffee() { return new McDonalCoffee(); } @Override public Hamburg getHamburg() { return new McDonalHamburg(); } } class KFCFactory implements AbstractFactory { @Override public Coffee getCoffee() { return new KFCCoffee(); } @Override public Hamburg getHamburg() { return new KFCHamburg(); } } class WallaceFactory implements AbstractFactory { @Override public Coffee getCoffee() { return new WallaceCoffee(); } @Override public Hamburg getHamburg() { return new WallaceHamburg(); } } public class Demo { public static void main(String[] args) { AbstractFactory abstractFactory = new McDonaldFactory(); abstractFactory.getCoffee().getName(); abstractFactory.getHamburg().getName(); abstractFactory = new KFCFactory(); abstractFactory.getCoffee().getName(); abstractFactory.getHamburg().getName(); abstractFactory = new WallaceFactory(); abstractFactory.getCoffee().getName(); abstractFactory.getHamburg().getName(); } }
Output results:
class demo4.McDonalCoffee
class demo4.McDonalHamburg
class demo4.KFCCoffee
class demo4.KFCHamburg
class demo4.WallaceCoffee
class demo4.WallaceHamburg
In fact, we can do the same