Data study organized from: Station B is still Silicon Valley
I wrote a set of code to understand by myself, which has been uploaded Code cloud
Since the design pattern is a big topic with a lot of content, my plan is to learn some commonly used ones first, and then gradually make them comprehensive.
Design Patterns
Design Pattern
Concept introduction
1) Design patterns are useful experiences summed up by programmers in the face of similar software engineering design problems, and are general solutions to certain types of problems. Design patterns represent the best practices. These solutions are the result of a considerable period of trial and error by numerous software developers.
2) The nature of the design pattern improves the maintainability, versatility and scalability of the software, and reduces the complexity of the software.
type
The 23 design patterns are grouped into three types:
1) Creation mode: singleton mode, abstract factory mode, factory mode, prototype mode, builder mode;
2) Structural mode: adapter mode, bridge mode, decoration mode, combination mode, appearance mode, flyweight mode, proxy mode;
3) Behavioral patterns: template method pattern, command pattern, visitor pattern, iterator pattern, observer pattern, mediator pattern, memorandum pattern, interpreter pattern (Interpreter), state pattern, strategy pattern, responsibility chain pattern (responsibility chain pattern) chain).
1. Singleton pattern (creative type)
Definition: In the entire software system, ensure that there is only one instance of a class, and only provide one entry to obtain the instance.
Scenes
Heavyweight objects that don't require multiple instances. Such as: thread pool, database connection pool, etc.
Implementation:
1. Hungry Chinese style (static constant)
private Singleton(){} private static Singleton singleton = new Singleton(); public Singleton getInstance(){ return singleton; }
Conclusion: May be a waste of memory.
2. Hungry Chinese style (static code block)
private Singleton(){} private static Singleton singleton; static{ if(singleton==null){ singleton = new Singleton(); } } public Singleton getInstance(){ return singleton; }
Conclusion: May be a waste of memory.
3. Lazy (single thread)
private Singleton(){} private static Singleton singleton; public Singleton getInstance(){ if(singleton==null){ singleton = new Singleton(); } return singleton; }
Conclusion: Multithreading is not safe. Do not use.
4. Lazy (synchronized method)
private Singleton(){} private static Singleton singleton; public static synchronized Singleton getInstance(){ if(singleton==null){ singleton = new Singleton(); } return singleton; }
Conclusion: The efficiency is too low. Not recommended.
5. Lazy man style (synchronized code block)
private Singleton(){} private static Singleton singleton; public static Singleton getInstance(){ if(singleton==null){ synchronized(Singleton.class){ singleton = new Singleton(); } } return singleton; }
Conclusion: Multithreading is not safe. Do not use.
6. Lazy Man (DCL Double Check)
private Singleton(){} private static volatile Singleton singleton; public static Singleton getInstance(){ if(singleton == null){ synchronized(Singleton.class){ if(singleton == null){ singleton = new Singleton(); } } return singleton; } }
Conclusion: lazy loading, thread safety, and guaranteed efficiency. Recommended Use.
7. Static inner class
private Singleton(){} private static class SingletonInstance{ private static final Singleton INSTANCE = new Singleton(); } public static Singleton getInstance(){ return SingletonInstance.INSTANCE; }
1) The static inner class will not be executed when the outer class is loaded. When the getInstance is called, the static inner class will be loaded: lazy loading;
2) Use the mechanism of jvm class loading to ensure that only one thread executes when an instance is initialized, and static properties are only initialized when the class is loaded for the first time: thread safety;
Conclusion: lazy loading, thread-safe and efficient. Recommended Use.
8. Enumeration
enum Singleton(){ INSTANCE; }
The enumeration added by JDK1.5 is a singleton, and the re-creation of the instance is directly prohibited in the reflection source code. It is the way advocated by Effective Java author Josh Bloch.
Decompile the enumeration class and know that the enumeration belongs to the hungry Chinese style (static code block)
Application scenarios:
-
Objects that need to be created and destroyed frequently;
-
Objects that take a long time or consume too many resources when creating objects, but often used objects and tool classes
-
Frequently accessed objects that are databases or files (data sources, session factories, etc.)
2. Factory method pattern (creation type)
# Factory Pattern: Taking Songwriting as an Example The operation of writing a song is the same: - compose compose() - write lyrics lyrics() - arranger arrangement() - recording recording() There are many genres of songs: - ballad ballad - R&B RB - rock rock - rap rap
Simple Factory Pattern
When the code is completed, a new song type needs to be added: jazz It only takes two steps and does not affect other original song types 1,create JazzSong Class that implements internal business methods 2,Add a type judgment to the factory class
/** * Simple Factory Pattern * @author: stone * @create: 2020-09-16 00:08 */ public class SimpleFactory { ISong song; public ISong getSong(String songType){ if("ballad".equalsIgnoreCase(songType)){ song = new BalladSong(); }else if("rb".equalsIgnoreCase(songType)){ song = new RBSong(); }else if("rock".equalsIgnoreCase(songType)){ song = new RBSong(); }else if("rap".equalsIgnoreCase(songType)){ song = new RBSong(); }else if("jazz".equalsIgnoreCase(songType)){ song = new JazzSong(); }else{ song = null; } return song; } }
Factory Method Pattern
Defines an abstract method for creating an object, and it is up to the subclass to decide which class to instantiate. The Factory Method pattern defers instantiation of objects to subclasses.
Personal understanding: create a sub-factory class to inherit the original simple factory class, the production methods in the original simple factory class are inherited and implemented by the sub-factory class, and the original factory class is upgraded to an abstract class. The sub-factory class represents an extension in one dimension, and the product class represents an extension in another dimension. And the method produced in the original simple factory class sinks into the concrete sub-factory class, which is called method sinking/postponing, hence the name factory method model!
ISong song; String countryName; //The method of creating a specific song sinks into the specific sub-factory class public abstract ISong getSong(String songType); public void makeSong(){ do{ BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in)); System.out.println("Please enter the type of song you want to write:"); try { ISong song = getSong(bufferedReader.readLine()); if(song==null){ System.out.println("say good bye ~~"); break; } song.compose(); song.lyrics(); song.arrangement(); song.recording(); } catch (IOException e) { e.printStackTrace(); } }while (true); }
public class ChinaFactory extends BaseFactory { @Override public ISong getSong(String songType) { if("ballad".equalsIgnoreCase(songType)){ song = new BalladSongChina(); }else if("rap".equalsIgnoreCase(songType)){ song = new RapSongChina(); }else{ song = null; } return song; } }
3. Abstract Factory Pattern (creative)
An interface is defined for creating a cluster of related or dependent objects without specifying a specific class.
The abstract factory pattern can integrate the simple factory pattern and the factory method pattern.
The factory is abstracted into two layers, AbsFactory (abstract factory) and the factory subclass of concrete implementation. Engineers can use the corresponding factory subclass depending on the type of object being created. This turns a single simple factory class into a factory cluster, which is more conducive to code maintenance and expansion.
/** * abstract factory class * @author: stone * @create: 2020-09-17 22:52 */ public interface AbsFactory { /** * The specific business of writing songs is implemented by subclasses * @param type * @return */ ISong makeSong(String songType); }
/** * specific factory class * @author: stone * @create: 2020-09-16 01:50 */ public class ChinaFactory implements AbsFactory { @Override public ISong makeSong(String songType) { ISong song; if("ballad".equalsIgnoreCase(songType)){ song = new BalladSongChina(); }else if("rap".equalsIgnoreCase(songType)){ song = new RapSongChina(); }else{ song = null; } return song; } }
A key point is to establish a factory interface class, and subclasses inherit and implement specific content.
Use an interface factory to receive calls when used.
Factory Pattern Summary
Extract the code of the instantiated object and put it into a class for unified management and maintenance, so as to achieve decoupling from the main project dependency, thereby improving the extension and maintainability of the project. (relying on the principle of abstraction)
- When creating an object instance, do not directly new the class, but put the new action in a method of ICBC and return it. (Some books say: variables do not directly hold specific class references);
- Don't let classes inherit concrete classes, but inherit abstract classes or implement interfaces;
- Do not override methods already implemented in base classes.
4. Prototype mode (creative type)
5. Builder mode (creative type)
6. Adapter mode (structural type)
7. Bridge mode (structural type)
8. Decorator pattern (structural)
Resolve class explosion
definition:
Decorated with patterns that dynamically attach new functionality to objects.
In terms of object function extension, it is more flexible than inheritance, and the decoration pattern also reflects the open-closed principle (ocp);
A bit of constructor recursion
need:
Starbucks Coffee Order Items 1)Type of coffee/Single Origin Coffee: Espresso(espresso), ShortBlack,LongBlack(American coffee), Decaf(decaf) 2)seasoning: Milk,Soy(soy milk), Chocolate 3)request to expand**new coffee types**It has good expansibility, easy modification and maintenance. 4)Use an object-oriented approach to calculate the cost of different types of coffee: the customer can order a single coffee, or a single coffee+seasoning
Use the decorator pattern to solve:
/** * base class drink * @author: stone * @create: 2020-09-18 00:03 */ @Data public abstract class Drink { public String name; public double price; /** * Calculate the price * @return */ public abstract double cost(); }
/** * base class for decorators * @author: stone * @create: 2020-09-18 00:19 */ @Data public abstract class Decorator extends Drink { //Add composition relationship private Drink drinkObj; /** * Pass in the body that needs to be decorated * @param drinkObj */ public Decorator(Drink drinkObj){ this.drinkObj = drinkObj; } /** * Realize specific business * Calculation formula: price of seasoning + price of single-origin coffee */ @Override public double cost() { return super.getPrice() + drinkObj.cost(); } }
/** * @author: stone * @create: 2020-09-18 00:36 */ public class TestMain { public static void main(String args[]){ //1. Have an Italian coffee Drink drink = new Espresso(); System.out.println("1,have an Italian coffee:"); System.out.println(drink.name + " The price is: " + drink.cost()); System.out.println("====================================="); //2, add a milk drink = new PureMilk(drink); System.out.println("2,Add a serving of pure milk (double the price of milk)~):"); System.out.println(drink.name + " The price is: " + drink.cost()); System.out.println("====================================="); //3. Add a chocolate drink = new Chocolate(drink); System.out.println("3,add a chocolate:"); System.out.println(drink.name + " The price is: " + drink.cost()); System.out.println("====================================="); System.out.println("=== Business needs. To expand a decaffeinated coffee, you only need to add a main class, which can be matched with all ingredients arbitrarily ==="); System.out.println("====================================="); //Business needs. Extend a Decaf //1. Have a decaf Drink drink2 = new Decaf(); System.out.println("1,have a decaf:"); System.out.println(drink2.name + " The price is: " + drink2.cost()); System.out.println("====================================="); } }
The code has been uploaded to the code cloud, so it will not be posted
console
1,have an Italian coffee: Italian Coffee Price is: 15.5 ===================================== 2,Add a serving of pure milk (double the price of milk)~): Pure Milk Price is: 25.5 ===================================== 3,add a chocolate: Chocolate Price is: 28.5 ===================================== === Business needs. To expand a decaffeinated coffee, you only need to add a main class, which can be matched with all ingredients arbitrarily === ===================================== 1,have a decaf: Decaf Coffee Price is: 10.88 ===================================== Process finished with exit code 0
summary
The key lies in the abstraction of the base class, and then the "combination" of the decoration class and the theme: passing the decorator into the decoration class.
//decorator public abstract class Decorator extends Drink { //Add composition relationship private Drink drinkObj; }
Solve the problem of class explosion caused by the full combination of seasonings and single products.
9. Combination mode (structural type)
10. Appearance mode (structural type)
11. Flyweight mode (structural type)
12. Proxy mode (structural type)
Proxy
basic introduction
- Proxy pattern: Provides a stand-in for an object to control access to this object. That is, the target object is accessed through the proxy object. In this way, additional functional operations can be enhanced based on the realization of the target object. (i.e. extend the functionality of the target object)
- The proxied object can be a remote object, an object that is expensive to create, or an object that requires security controls.
- There are three forms of proxy mode: static proxy, dynamic proxy, Cglib proxy
- static proxy
- Dynamic proxy: also called JDK proxy, interface proxy
- Cglib proxy: Objects can be dynamically created in memory without implementing interfaces, and are also dynamic proxies.
static proxy
basic introduction:
When a static proxy is used, an interface or a parent class needs to be defined, and the proxied object (that is, the target object) implements the same interface or inherits the same parent class together with the proxy object.
/** * abstract class * Declare the method that needs to be executed * @author: stone * @create: 2020-09-18 21:42 */ public abstract class ITeacherDao { public abstract void teach(); }
/** * @author: stone * @create: 2020-09-18 21:48 */ public class TestMain { public static void main(String args[]){ //target ITeacherDao teacherDao = new TeacherDao(); //proxy class ITeacherDao teacherProxy = new TeacherProxy(teacherDao); //Execute the method of the proxy class to indirectly call the target class teacherProxy.teach(); } }
console
The agent teacher is here~~~ target teacher in class~~ The acting teacher is gone~~~ Process finished with exit code 0
Advantages and disadvantages of static proxy:
# advantage: On the premise of not modifying the function of the target object, the target function can be extended through the proxy object. # shortcoming: Because the proxy class needs to implement or inherit the same interface or parent class as the target class, many proxy classes need to be written. Once the interface or parent class adds methods, both the target class and the proxy class need to be modified and added.
Dynamic proxy
JDK proxy, interface proxy
basic introduction:
- The proxy class does not need to implement the interface or inherit the parent class, but the target class still needs to implement the interface or inherit the parent class
- The generation of the proxy class is to use the JDK API to dynamically build the proxy object in memory
API for generating proxy objects in JDK:
- In the package: java.lang.reflect.Proxy
- JDK implementation of a proxy only needs to use the newProxyInstance method:
static Object newProxyInstacne(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)
Code:
/** * Dynamic proxy mode * target class * @author: stone * @create: 2020-09-19 00:49 */ public class TeacherDao implements ITeacherDao{ @Override public void teach() { System.out.println("dynamic proxy is teaching !!!"); } @Override public String sayHi(String word) { System.out.println("hi "+word); return "Qilixiang"; } }
/** * Dynamic proxy mode * agency factory * Does not inherit any class, can dynamically proxy any class * @author: stone * @create: 2020-09-19 00:51 */ public class ProxyFactory { //Receive the target object that needs to be proxied Object target; public ProxyFactory(Object target){ this.target = target; } /** * Create a proxy instance of the target class * @return */ public Object getProxyInstance(){ /** * Implemented using the Radiation API * * Source code: public static Object newProxyInstance(ClassLoader loader, * Class<?>[] interfaces, * InvocationHandler h) * 1,loader: class loader for the target class * 2,interfaces: target class * 3,Event processing object (that is, the specific method/function/event of the proxy) */ return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { //Here it is: When the method of the target object is called, the event is triggered System.out.println("ProxyFactory invoke is action. args: "+args.toString()); Object retuenVal = method.invoke(target, args); System.out.println("ProxyFactory invoke is done."); return retuenVal; } }); } }
/** * application * @author: stone * @create: 2020-09-19 01:02 */ public class Client { public static void main(String args[]){ //target ITeacherDao teacherDao = new TeacherDao(); //proxy class ProxyFactory proxyFactory = new ProxyFactory(teacherDao); //Create proxy objects using proxy classes ITeacherDao proxyTeacherDao = (ITeacherDao) proxyFactory.getProxyInstance(); //Execute method using proxy object // proxyTeacherDao.teach(); System.out.println("hello " +proxyTeacherDao.sayHi("stone like heart")); } }
console:
ProxyFactory invoke is action. args: [Ljava.lang.Object;@61bbe9ba hi stone like heart ProxyFactory invoke is done. hello Qilixiang Process finished with exit code 0
Cglib proxy
subclass proxy
basic introduction:
- Both the waiting proxy and the JDK proxy require the target object to implement an interface, but sometimes it is just a separate class and does not implement any interface. In this case, the target object subclass can be used to implement it;
- Cglib proxy is to build a subclass object in memory to realize the function extension of target object, so sometimes it can be said that Cglib proxy belongs to dynamic proxy;
- Cglib is a powerful high-performance code generation package that can extend java classes and implement java interfaces at runtime. Cglib is widely used in AOP frameworks, such as Spring AOP implementation method interception;
- The bottom layer of the Cglib package is to convert bytecode and generate new classes by using the bytecode processing framework ASM.
Instructions for use:
- Need to import jar packages: asm.jar, asm-commons.jar, asm-tree.jar, cglib-2.2.jar;
- Build a subclass in memory, and an error will be reported if the target object has final modification:
java.lang.IllegalArgumentException;
- If the method of the target object is final/static, it will not be intercepted, that is, the additional business methods of the target object will not be executed.
Code combat:
/** * Implement dynamic proxy using cglib framework * * @author: stone * @create: 2020-09-19 14:52 */ public class ProxyFactory implements MethodInterceptor { //Receive proxy target object Object target; //Constructor public ProxyFactory(Object target){ this.target = target; } /** * Methods for generating proxy objects * Here the proxy object is generated using the cglib method * Simple understanding: construct a subclass for the target class, and then create the parent class through the subclass to get the target object * @return */ public Object getProxyInstance(){ //1. Load the cglib tool class Enhancer Enhancer enhancer = new Enhancer(); //2. Set the target class as the parent class enhancer.setSuperclass(target.getClass()); //3. Set the callback method enhancer.setCallback(this); //4. Generate a proxy object for the target object return enhancer.create(); } /** * intercept method * @param o * @param method Executed concrete class * @param objects parameter list * @param methodProxy * @return The return value of the target method may be null * @throws Throwable */ @Override public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { System.out.println("cglib Proxy mode interception starts~ ~"); Object returnVal = method.invoke(target, objects); System.out.println("cglib Proxy mode interception ends~ ~"); return returnVal; } }
console:
cglib Proxy mode interception starts~ ~ hi stone like heart cglib Proxy mode interception ends~ ~ hello Qilixiang
summary:
Simple understanding: construct a subclass for the target class, and then create the parent class through the subclass to get the target object
Examples of application scenarios
- Firewall proxy
The intranet penetrates the firewall through the proxy to achieve access to the public network.
- caching proxy
When requesting resources such as image files, first go to the caching proxy to get them. If you cannot get the resources, then go to the public network or database to get them and store them in the caching proxy.
- remote proxy
A local representation of a remote object through which the remote object can be invoked as a local object. The remote agent communicates with the real remote object over the network.
- Sync agent
Mainly used in multi-threaded programming to encapsulate synchronization processing (locks) for resource objects.
13. Template method pattern (behavioral)
14. Command mode (behavioral)
15. Visitor pattern (behavioral)
16. Iterator mode (behavioral)
17. Observer mode (behavioral)
Business scene:
Weather forecast items:
- The weather station publishes the temperature, humidity, air pressure and other information measured every day in the form of announcements;
- An open API needs to be designed to facilitate other third parties to obtain measured meteorological data;
- Provide interface for temperature, humidity and air pressure;
- When the measurement data is updated, it should be able to notify the third party in real time.
Common solution implementation:
/** * weather information weather station * Enter the measured data into the system * @author: stone * @create: 2020-09-19 15:48 */ @Data public class WeatherData { private float temperatrue;//temperature private float humidity;//humidity private float pressure;//air pressure //third party CCTV cctv = new CCTV(); /** * update data */ public void updateData(float temperatrue,float humidity,float pressure){ this.temperatrue = temperatrue; this.humidity = humidity; this.pressure = pressure; //The weather has been updated, and the data will be pushed out //CCTV cctv.showWeather(temperatrue,humidity,pressure); } }
Code test
Observer pattern principle
Weather station is Subject
The third party is Observer
Third party to observe the weather station
/** * Use the observer pattern * observer * @author: stone * @create: 2020-09-19 17:14 */ public interface Observer { // Receive weather information public void showWeather(float temperatrue,float humidity,float pressure); }
/** * Use the observer pattern * data provider * @author: stone * @create: 2020-09-19 17:13 */ public interface Subject { /** * update data */ public void updateData(float temperatrue,float humidity,float pressure); }
/** * @author: stone * @create: 2020-09-19 15:56 */ public class ClientMain { public static void main(String args[]){ //third party Observer cctv = new CCTV(); Observer baidu = new Baidu(); Observer tencent = new Tencent(); WeatherData weatherData = new WeatherData(); //Registering a third party is very easy to expand weatherData.registerObserver(cctv); weatherData.registerObserver(baidu); weatherData.registerObserver(tencent); //New weather information measured weatherData.updateData(29,70,1006); } }
summary:
Similar to the message queue mode, the observer registers with the publishing center, and then when I have a message, I push it to the publishing center, and the publishing center sends it to all registered observers.
18. Mediator model (behavioral)
19. Memo mode (behavioral)
20. Interpreter mode (behavioral)
Interpreter mode
21. State mode (behavioral)
22. Strategy mode (behavioral)
23. Chain of Responsibility Model (Behavioral)
Chain of Responsibility Model