Design pattern principle
- The opening and closing principle is open to extensions and closed to modifications.
- The dependency inversion principle realizes loose coupling by abstracting so that various classes or modules do not affect each other.
- Single responsibility principle a class, interface and method only do one thing.
- The interface isolation principle tries to ensure the purity of the interface, and the client should not rely on unnecessary interfaces.
- Dimitri's law is also called the least known principle. The less a class knows about the class it depends on, the better.
- The subclass of Richter replacement principle can extend the function of the parent class, but cannot change the original function of the parent class.
- The principle of composite reuse tries to use object combination and aggregation instead of inheritance to achieve the purpose of code reuse.
Simple factory mode
This type of design pattern is a creation pattern, which provides the best way to create objects.
In factory mode, when creating objects, we do not expose the creation logic to the client, and point to the newly created objects by using a common interface.
Disadvantages: the expansibility is not good, which violates the opening and closing principle and closes the modification
Factory class
You can see that our factory class provides creation methods. There are three methods to create different products
/** * @Author jyl * @Date 2021/12/9 16:18 * @Version 1.0 * Simple factory class */ public class ICourseFactory { /*The creation mode of the first version has disadvantages because name cannot be detected*/ // public ICourse create(String name){ // if("java".equals(name)){ // return new JavaCourse(); // }else if("python".equals(name)){ // return new PythonCourse(); // }else { // return null; // } // } /*The second version is created according to the full class name*/ // public ICourse create(String className){ // try { // if (!(null == className || "".equals(className))) { // return (ICourse) Class.forName(className).newInstance(); // } // // }catch (Exception e){ // e.printStackTrace(); // } // return null; // } /*The third edition was created using reflection*/ public ICourse create(Class<? extends ICourse> clazz){ try { if (null != clazz) { return clazz.newInstance(); } }catch (Exception e){ e.printStackTrace(); } return null; } }
Product category
Here we can see that one product type is course recording. Our two specific products record java courses and python courses. They both implement course recording methods. Only the content of course recording is different, that is, the specific implementation classes are different. The print recording java recording Python here represents the common interfaces of different logical product classes of different products
The disadvantage of this is that we have to modify our factory class every time we extend a code. Because of this problem, all factory method patterns appear
/** * @Author jyl * @Date 2021/12/9 16:14 * @Version 1.0 * Recording video interface */ public interface ICourse { /** * record video * @return */ void record(); }
java course
/** * @Author jyl * @Date 2021/12/9 16:15 * @Version 1.0 * Subclass */ public class JavaCourse implements ICourse { public void record() { System.out.println("Recording Java curriculum"); } }
python course
/** * @Author jyl * @Date 2021/12/9 16:15 * @Version 1.0 * Subclass */ public class PythonCourse implements ICourse { public void record() { System.out.println("Recording Python curriculum"); } }
Client call
/** * @Author jyl * @Date 2021/12/9 16:21 * @Version 1.0 * Simple factory client */ public class SimpleFactoryTest { public static void main(String[] args) { /*Do not use factory configuration*/ // ICourse course = new JavaCourse(); // course.record(); // /*First edition configuration*/ // ICourseFactory factory = new ICourseFactory(); // ICourse course = factory.create("java"); // course.record(); /*The second version of factory configuration uses the full class name*/ // ICourseFactory factory = new ICourseFactory(); // ICourse course = factory.create("yongli.product.impl.JavaCourse"); // course.record(); ICourseFactory factory = new ICourseFactory(); ICourse course = factory.create(JavaCourse.class); course.record(); /*Simple factory pattern case for date class jdk*/ Calendar.getInstance(); /*slf4j Using simple factory cases*/ LoggerFactory.getLogger(SimpleFactoryTest.class); }
Calendar. Example of getInstance using simple factory pattern
LoggerFactory.getLogger(); Example of using simple factory mode
switch case here is a simple factory
Simple factory method model
You can see that the factory abstraction is shared with the creation of each product to each specific factory. At this time, there must be people like me. Why can't we directly new objects? You can think about the factory pattern to solve the problems during creation. For example, I have many setget specific creation methods for constructing this object, and some things don't want to be exposed to the client To produce this, the use of this factory is too single, and a factory can only produce one product
Abstract factory interface
/** * @Author jyl * @Date 2021/12/9 17:14 * @Version 1.0 * Factory method mode interface */ public interface ICourseFactory { ICourse create(); }
Specific factories that implement factory interfaces
/** * @Author jyl * @Date 2021/12/9 17:15 * @Version 1.0 * The method factory mode is used to create a product creation factory with shared responsibility */ public class JavaCourseFactory implements ICourseFactory { public ICourse create() { return new JavaCourse(); } }
/** * @Author jyl * @Date 2021/12/9 17:15 * @Version 1.0 */ public class PythonCourseFactory implements ICourseFactory { public ICourse create() { return new PythonCourse(); } }
Client call
/** * @Author jyl * @Date 2021/12/9 16:21 * @Version 1.0 * Method factory client */ public class FactorymethodTest { public static void main(String[] args) { ICourseFactory iCourseFactory = new JavaCourseFactory(); iCourseFactory.create().record(); } }
Abstract factory pattern
Abstract factory pattern refers to providing an interface to create a series of related or interdependent objects without specifying their specific classes. The client (application layer) does not depend on the details of how product class instances are created and implemented. It emphasizes that a series of related product objects (belonging to the same product family) are used together, and creating objects requires a lot of repeated code. It is necessary to provide a library of product classes, and all products appear with the same interface, so that the client does not depend on the specific implementation.
Concept of product family
In the past, we added a new product every time, and now we add a new product family every time. For example, in the past, we used a course recording factory to implement java course recording factory class and python course recording factory class, and the note factory to add note factory class, Java notes and python notes. Now we directly extract them into a comprehensive factory called java course super The factory is equivalent to the integration of Java note factory and Java note factory, and so is the python super factory at this time
Even if golang c + + is released in the future, it will only add a super factory. Because these super factories are a product family, they are abstracted as an interface for everyone to inherit
It can be seen from the above figure that there are three kinds of graphics: square, circle and diamond. The one with the same color represents the same product family, and the one with the same shape represents the same product grade structure. For example, Midea produces a variety of household appliances. In the above figure, the darkest square represents the beautiful washing machine, the darkest circle represents the beautiful air conditioner, and the darkest diamond represents the beautiful water heater. The darkest row belongs to the brand of beauty and belongs to the product family of beauty appliances. Look at the diamond on the far right. We have designated the deepest color to represent the beautiful water heater, and the slightly lighter diamond in the second row represents the water heater of Hisense. Similarly, under the same product structure, there are Gree water heater, Gree air conditioner and Gree washing machine.
Looking at the following picture, we think that there are specific factories, including Meidi factory, Hisense factory and Gree factory. Each brand of factory produces washing machines, water heaters and air conditioners.
Top level abstract factory
/** * @Author jyl * @Date 2021/12/9 19:57 * @Version 1.0 * Top level abstract factory pattern * Each time a new product family is created, a new creation method is added */ public interface CourseFactory { /*Create note products*/ INote createINote(); /*Create course recording products*/ IVideo createIVideo(); }
java course product family factory
/** * @Author jyl * @Date 2021/12/9 20:06 * @Version 1.0 * java The factory class of the product family implements the abstract factory interface */ public class JavaCourseFactory implements CourseFactory { public JavaINoteImpl createINote() { return new JavaINoteImpl(); } public IVideo createIVideo() { return new JavaIVideoImpl(); } }
Product hierarchy interface
Category is a product hierarchy
/** * @Author jyl * @Date 2021/12/9 20:00 * @Version 1.0 * Class notes product family */ public interface INote { /*Take notes*/ void edit(); }
/** * @Author jyl * @Date 2021/12/9 20:00 * @Version 1.0 */ /*Interface of course recording product family*/ public interface IVideo { /*Video recording*/ void record(); }
Concrete implementation of java products
/** * @Author jyl * @Date 2021/12/9 20:05 * @Version 1.0 * java Note products */ public class JavaINoteImpl implements INote { public void edit() { System.out.println("I'm writing java note"); } }
/** * @Author jyl * @Date 2021/12/9 20:06 * @Version 1.0 * java Course recording products */ public class JavaIVideoImpl implements IVideo { /*Video recording*/ public void record() { System.out.println("I'm recording java video"); } }
java client call
/** * @Author jyl * @Date 2021/12/13 8:50 * @Version 1.0 */ public class AbstractFactoryTest { public static void main(String[] args) { CourseFactory factory = new JavaCourseFactory(); /*Create note products*/ factory.createINote().edit(); /*Create course recording products*/ factory.createIVideo().record(); } }
Add a python product race
Through the above, we can wear a product race of java products
We're going to add a python product race
python course product family factory
/** * @Author jyl * @Date 2021/12/13 8:54 * @Version 1.0 * * python Product family factory */ public class PythonCourseFactory implements CourseFactory { public INote createINote() { return new PythonINoteImpl(); } public IVideo createIVideo() { return new JavaIVideoImpl(); } }
Specific implementation of Python products
/** * @Author jyl * @Date 2021/12/13 8:55 * @Version 1.0 */ public class PythonINoteImpl implements INote { public void edit() { System.out.println("write python note"); } }
/** * @Author jyl * @Date 2021/12/13 8:56 * @Version 1.0 */ public class PythonIVideoImpl implements IVideo { public void record() { System.out.println("python Class recording"); } }
We can see that we have added a new product family. We only need to implement the abstract factory and the defined product structure to realize a product race
Add a new product
Now we not only record lessons and write notes, but also look at the source code, so we need to add a product structure, that is, look at the source code ISource
We are now adding a new product to our abstract factory
Abstract factory class change
/** * @Author jyl * @Date 2021/12/9 19:57 * @Version 1.0 * Top level abstract factory pattern * Each time a new product family is created, a new creation method is added */ public interface CourseFactory { /*Create note products*/ INote createINote(); /*Create course recording products*/ IVideo createIVideo(); /*Create source code products*/ ISource createISource(); }
Factory changes
/** * @Author jyl * @Date 2021/12/9 20:06 * @Version 1.0 * java The factory class of the product family implements the abstract factory interface */ public class JavaCourseFactory implements CourseFactory { public JavaINoteImpl createINote() { return new JavaINoteImpl(); } public IVideo createIVideo() { return new JavaIVideoImpl(); } public ISource createISource() { return new JavaISourceImpl(); } }
/** * @Author jyl * @Date 2021/12/13 8:54 * @Version 1.0 * * python Product family factory */ public class PythonCourseFactory implements CourseFactory { public INote createINote() { return new PythonINoteImpl(); } public IVideo createIVideo() { return new JavaIVideoImpl(); } public ISource createISource() { return new PythonISourceImpl(); } }
New product interface
/** * @Author jyl * @Date 2021/12/13 9:06 * @Version 1.0 * Source product structure */ public interface ISource { void look(); }
Add specific product realization class
/** * @Author jyl * @Date 2021/12/13 9:12 * @Version 1.0 * java Source product */ public class JavaISourceImpl implements ISource { public void look() { System.out.println("I'm watching. Java Source code"); } }
/** * @Author jyl * @Date 2021/12/13 9:13 * @Version 1.0 * python product */ public class PythonISourceImpl implements ISource { public void look() { System.out.println("I'm watching. python Source code"); } }
The above code completely describes two product family Java courses and Python courses, as well as two product level videos and notes. The abstract factory perfectly and clearly describes such a complex relationship. However, I wonder if you have found that if we continue to expand the product level and add the Source code to the course, our code will have to be adjusted from the abstract factory to the specific factory, which obviously does not comply with the opening and closing principle.
Therefore, abstract factories also have disadvantages:
1. It specifies all product sets that may be created. It is difficult to expand new products in the product family, and the interface of the abstract factory needs to be modified.
2. It increases the abstraction and understanding difficulty of the system. However, in practical application, we must not commit obsessive-compulsive disorder or even cleanliness. In the actual demand, upgrading the product hierarchy is a very normal thing. According to the actual situation, we can not follow the opening and closing principle as long as we do not upgrade frequently. Why not upgrade the code every six months or every year?