1. Overview
Overall, design patterns are divided into three categories:
(1) Creative mode , a total of five types: factory method mode, abstract factory mode, singleton mode, builder mode, and prototype mode.
(2) Structural modes , a total of seven types: adapter mode, decorator mode, proxy mode, appearance mode, bridge mode, combination mode, and enjoyment mode.
(3) Behavioral mode , a total of eleven: policy mode, template method mode, observer mode, iterative sub-mode, responsibility chain mode, command mode, memo mode, status mode, visitor mode, intermediary mode, and interpreter mode.
2. Six principles of design model
1. Open Close Principle
The principle of opening and closing is to open to extensions and close to modifications. When the program needs to be expanded, you cannot modify the original code to achieve a hot plug effect.
2. Liskov Substitution Principle
Its official description is relatively abstract and can be used to Baidu. In fact, it can be understood as follows: (1) The ability of a subclass must be greater than or equal to the parent class, that is, the methods that the parent class can use, and the subclass can use. (2) The same is true for the return value. Suppose a parent class method returns a List and a subclass returns an ArrayList, which of course can be done. If the parent class method returns an ArrayList and the child class returns a List, it doesn't make sense. Here the ability of subclasses to return values is smaller than that of parent classes. (3) There are also cases where exceptions are thrown. Any subclass method can declare a subclass that throws the parent class method to declare an exception.
It cannot declare that the exception that the parent class has not declared is thrown.
3. Dependence Inversion Principle
This is the basis of the principle of opening and closing, and the specific content: interface-oriented programming, relying on abstraction rather than concrete.
4. Interface Segregation Principle
This principle means: using multiple isolated interfaces is better than using a single interface. It also means reducing the coupling degree between classes. From here we can see that the design pattern is actually the design idea of a software, starting from a large software architecture, for the convenience of upgrading and maintenance. Therefore, the above article has appeared many times: reduce dependence and reduce coupling.
5. Demeter Principle
Why is the principle of least knowledge? That is, one entity should interact with other entities as little as possible, so that the system functional modules are relatively independent.
6. Composite Reuse Principle
The principle is to try to use synthesis/aggregation methods rather than inheritance.
3. Creation mode
There are five types of creation modes: factory method mode, abstract factory mode, singleton mode, builder mode, and prototype mode.
3.1. Factory method model
The factory method mode is divided into three types: ordinary factory mode, multiple factory method mode and static factory method mode.
3.1.1. Ordinary factory model
The ordinary factory model is to establish a factory class and create instances of some classes that implement the same interface.
package com.mode.create; public interface MyInterface { public void print();} package com.mode.create; public class MyClassOne implements MyInterface { @Override public void print() { System.out.println("MyClassOne"); } } package com.mode.create; public class MyClassTwo implements MyInterface { @Override public void print() { System.out.println("MyClassTwo"); } } package com.mode.create; public class MyFactory { public MyInterface produce(String type) { if ("One".equals(type)) { return new MyClassOne(); } else if ("Two".equals(type)) { return new MyClassTwo(); } else { System.out.println("No type to be found"); return null; } } } package com.mode.create; public class FactoryTest { public static void main(String[] args){ MyFactory factory = new MyFactory(); MyInterface myi = factory.produce("One"); myi.print(); } }I think the results of FactoryTest should be obvious.
Let’s understand this sentence again: the ordinary factory model is to establish a factory class and create instances of some classes that implement the same interface.
3.1.2. Multiple factory method modes
Multiple factory method modes are an improvement to the ordinary factory method mode. Multiple factory method modes are to provide multiple factory methods to create objects separately.
Let’s look at the code directly. We modify MyFactory and FactoryTest as follows:
package com.mode.create; public class MyFactory { public MyInterface produceOne() { return new MyClassOne(); } public MyInterface produceTwo() { return new MyClassTwo(); } } package com.mode.create; public class FactoryTest { public static void main(String[] args){ MyFactory factory = new MyFactory(); MyInterface myi = factory.produceOne(); myi.print(); } }The operation results are also very obvious.
Let’s understand this sentence again: Multiple factory method modes are an improvement to the ordinary factory method mode. Multiple factory method modes are to provide multiple factory methods to create objects separately.
3.1.3. Static factory method mode
Static factory method mode, set the methods in the above multiple factory method modes to static, and there is no need to create an instance, just call it directly.
Let’s look at the code directly. We modify MyFactory and FactoryTest as follows:
package com.mode.create; public class MyFactory { public static MyInterface produceOne() { return new MyClassOne(); } public static MyInterface produceTwo() { return new MyClassTwo(); } } package com.mode.create; public class FactoryTest { public static void main(String[] args){ MyInterface myi = MyFactory.produceOne(); myi.print(); } }The results of the operation are still very obvious.
Review again: Static factory method mode, set the methods in the above multiple factory method modes to static, and there is no need to create an instance, just call it directly.
3.2. Abstract factory pattern
There is a problem with the factory method model that class creation depends on factory classes, that is, if you want to expand the program, you must modify the factory class, which violates the closure principle.
To solve this problem, let’s take a look at the abstract factory pattern: create multiple factory classes, so that once new functions are needed, you can directly add new factory classes, without modifying the previous code.
This complies with the closure principle.
Let's take a look at the code below:
MyInterface, MyClassOne, MyClassTwo remains unchanged.
The following interfaces and classes are added:
package com.mode.create; public interface Provider { public MyInterface produce(); }package com.mode.create; public class MyFactoryOne implements Provider { @Override public MyInterface produce() { return new MyClassOne(); } }package com.mode.create; public class MyFactoryTwo implements Provider { @Override public MyInterface produce() { return new MyClassTwo(); } }Modify the test class FactoryTest as follows:
package com.mode.create; public class FactoryTest { public static void main(String[] args){ Provider provider = new MyFactoryOne(); MyInterface myi = provider.produce(); myi.print(); } }The operation results are still obvious.
Review again: The abstract factory pattern is to create multiple factory classes, so that once new functions are needed, you can directly add new factory classes, without modifying the previous code.
3.3. Singleton mode
Singleton pattern, no need for too much explanation.
Just look at the code:
package test; public class MyObject { private static MyObject myObject; private MyObject() { } public static MyObject getInstance() { if (myObject != null) { } else { myObject = new MyObject(); } return myObject; } }However, this will cause multi-threading problems. For a detailed explanation, you can see Chapter 6 in the book "Core Technology of Java Multi-threading Programming".
3.4. Builder Mode
Builder pattern: is to separate the construction of a complex object from its representation, so that the same construction process can create different representations.
It looks very abstract literally, but in fact it is also very abstract! ! ! !
The Builder Mode usually includes the following characters:
(1) Builder: Give an abstract interface to standardize the construction of various components of the product object. This interface specifies which parts of complex objects are created, and does not involve the creation of specific object components.
(2) ConcreteBuilder: Implements the Builder interface, and defines the creation of various parts of complex objects for different business logic. After the construction process is completed, an example of the product is provided.
(3) Director: Calls specific builders to create various parts of complex objects. The instructor does not involve specific product information, but is only responsible for ensuring that all parts of the object are created intact or in a certain order.
(4) Product: The complex object to be created.
It is common to build villains in game development, and the requirement is: villains must include head, body and feet.
Let's take a look at the following code:
Product (Complex object to be created.):
package com.mode.create; public class Person { private String head; private String body; private String foot; public String getHead() { return head; } public void setHead(String head) { this.head = head; } public String getBody() { return body; } public void setBody(String body) { this.body = body; } public String getFoot() { return foot; } public void setFoot(String foot) { this.foot = foot; }} Builder (Gives an abstract interface to standardize the construction of various components of a product object. This interface specifies which parts of a complex object are created to be implemented, and does not involve the creation of specific object components.):
package com.mode.create; public interface PersonBuilder { void buildHead(); void buildBody(); void buildFoot(); Person buildPerson();} ConcreteBuilder (Implements the Builder interface, which embodies the creation of various parts of complex objects for different business logic. After the construction process is completed, provide an example of the product.):
package com.mode.create; public class ManBuilder implements PersonBuilder { Person person; public ManBuilder() { person = new Person(); } public void buildBody() { person.setBody("Build the man's body"); } public void buildFoot() { person.setFoot("Build the man's feet"); } public void buildHead() { person.setHead("Build the man's head"); } public Person buildPerson() { return person; } } Director (Call the specific builder to create various parts of complex objects. The instructor does not involve specific product information. It is only responsible for ensuring that the parts of the object are created intact or in a certain order.):
package com.mode.create; public class PersonDirector { public Person constructPerson(PersonBuilder pb) { pb.buildHead(); pb.buildBody(); pb.buildFoot(); return pb.buildPerson(); }} Test class:
package com.mode.create; public class Test { public static void main(String[] args) { PersonDirector pd = new PersonDirector(); Person person = pd.constructPerson(new ManBuilder()); System.out.println(person.getBody()); System.out.println(person.getFoot()); System.out.println(person.getHead()); }}Running results:
Review: Builder pattern: is to separate the construction of a complex object from its representation, so that the same construction process can create different representations.
3.5. Prototype mode
The idea of this pattern is to use an object as a prototype, copy and clone it, and produce a new object similar to the original object.
Speaking of copying objects, I will talk about it in combination with shallow copying and deep copying of objects. First of all, you need to understand the concept of deep and shallow copying of objects:
Shallow copy: After copying an object, variables of the basic data type will be recreated, while the reference type points to the original object.
Deep copy: After copying an object, both the basic data type and the reference type are recreated. Simply put, deep copying is completely copied, while shallow copying is not thorough.
Write an example of copying depth:
package com.mode.create; import java.io.ByteArrayInputStream;import java.io.ByteArrayOutputStream;import java.io.IOException;import java.io.ObjectInputStream;import java.io.ObjectOutputStream;import java.io.Serializable; public class Prototype implements Cloneable, Serializable { private static final long serialVersionUID = 1L; private int base; private Integer obj; /* shallow copy*/ public Object clone() throws CloneNotSupportedException { // Because the Cloneable interface is an empty interface, you can define the method name of the implementation class at will // such as cloneA or cloneB, because the focus here is the sentence super.clone() // super.clone() calls the Object clone() method // In the Object class, clone() is a native (native method) Prototype proto = (Prototype) super.clone(); return proto; } /* deep copy*/ public Object deepClone() throws IOException, ClassNotFoundException { /* Write the binary stream to the current object*/ ByteArrayOutputStream bos = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(bos); oos.writeObject(this); /* Read out the new object generated by the binary stream*/ ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray()); ObjectInputStream ois = new ObjectInputStream(bis); return ois.readObject(); } public int getBase() { return base; } public void setBase(int base) { this.base = base; } public Integer getObj() { return obj; } public void setObj(Integer obj) { this.obj = obj; } } Test class:
package com.mode.create; import java.io.IOException; public class Test { public static void main(String[] args) throws CloneNotSupportedException, ClassNotFoundException, IOException { Prototype prototype = new Prototype(); prototype.setBase(1); prototype.setObj(new Integer(2)); /* shallow copy*/ Prototype prototype1 = (Prototype) prototype.clone(); /* Deep copy*/ Prototype prototype2 = (Prototype) prototype.deepClone(); System.out.println(prototype1.getObj()==prototype1.getObj()); System.out.println(prototype1.getObj()==prototype2.getObj()); }}Running results:
The above is all about this article, I hope it will be helpful to everyone's learning.