background
Are you still writing about explosions on the screen?
That is, regardless of 3721, write all the code in one class, so the code is not elegant. If the change involves the old code, it may also affect the stability of the online system.
In fact, in many cases, we can solve many potential system problems by skillfully using the design mode. Today, the stack leader will teach you to use the decorator mode and expand the functions without changing the old code. It can not only improve the elegance of the code, but also not affect the existing functions. Who uses it knows, it's really fragrant!!
What is decorator mode?
Decorator mode, literally understood, as the name suggests, is a decoration mode. It can package and decorate the existing objects and behaviors at a new level without changing the original code, and enhance the original basic functions to provide richer capabilities.
Take a simple example of decoration:
Cleaning > puttying > painting > hanging murals
It can also be:
Cleaning > puttying > pasting marble > hanging TV
Or it can be:
Cleaning > puttying > wallpaper
This is a simple step-by-step process of decorating the wall (ha ha, probably, I'm not professional). This is the decorator mode. Each step of decoration does not interfere with each other, but the later steps need to rely on the completion of the previous step, and the latter steps can be continuously added on the basis of the previous decoration.
The structure diagram of decorator mode is as follows:
The structure of decorator mode class is as follows:
- Component: component interface class, which defines the basic functions of the decorated class
- ConcreteComponent: basic implementation class of component interface
- Decorator: decorator role class, which implements and holds a Component object instance
- ConcreteDecorator: implementation class of decorator
Advantages of decorator mode:
1. Do not change the original code and dynamically add functions;
2. Objects are not interdependent, loosely coupled and elegant enough;
3. Comply with the opening and closing principle, with good expansibility and easy maintenance;
Disadvantages of decorator mode:
1. If there are many decorative links, it will cause the expansion of ornaments;
2. The nesting of decorators is complex. Users must be aware of all decorators and their uses;
Decorator mode actual combat
Let's use the decorator mode to realize the above decoration case.
Interface class component:
/** * Wall decoration interface * @author: Stack length * @from: Official account Java technology stack */ public interface WallBeautify { /** * Decoration operation * @author: Stack length * @from: Official account Java technology stack */ void operation(); }
Basic implementation classes of component interfaces:
/** * Wall decoration is basically realized (wall cleaning) * @author: Stack length * @from: Official account Java technology stack */ public class WallBeautifyClean implements WallBeautify { @Override public void operation() { System.out.println("Start cleaning the wall"); } }
Decorator role class:
This is an abstract class that implements and holds a Component object instance. Here, aggregation is used instead of inheritance, which is also the key point of decorator pattern.
/** * Role of wall decoration decorator * @author: Stack length * @from: Official account Java technology stack */ public abstract class WallBeautifyDecorator implements WallBeautify { /** * Hold a Component object instance * @author: Stack length * @from: Official account Java technology stack */ private WallBeautify wallBeautify; public WallBeautifyDecorator(WallBeautify wallBeautify) { this.wallBeautify = wallBeautify; } @Override public void operation() { wallBeautify.operation(); decoration(); } /** * Custom implementation method of decorator implementation class * @author: Stack length * @from: Official account Java technology stack */ public abstract void decoration(); }
Overwrite the original operation method and decorate it after the original operation. Therefore, it is necessary to provide an abstract decoration method for the implementation classes of different decorators.
Implementation class of decorator:
Three decoration processes are defined here:
Puttying > painting > hanging murals
Therefore, each inherits the decorator role class and implements its decoration method:
/** * Role realization of wall decoration decorator (puttying) * @author: Stack length * @from: Official account Java technology stack */ public class WallBeautifyPutty extends WallBeautifyDecorator { public WallBeautifyPutty(WallBeautify wallBeautify) { super(wallBeautify); } @Override public void decoration() { System.out.println("Start puttying"); } }
/** * Role realization of wall decoration decorator (painting) * @author: Stack length * @from: Official account Java technology stack */ public class WallBeautifyPaint extends WallBeautifyDecorator { public WallBeautifyPaint(WallBeautify wallBeautify) { super(wallBeautify); } @Override public void decoration() { System.out.println("Start painting"); } }
/** * Role realization of wall decoration decorator (hanging mural) * @author: Stack length * @from: Official account Java technology stack */ public class WallBeautifyHang extends WallBeautifyDecorator { public WallBeautifyHang(WallBeautify wallBeautify) { super(wallBeautify); } @Override public void decoration() { System.out.println("Start hanging murals"); } }
Test:
/** * Decorator pattern test class * @author: Stack length * @from: Official account Java technology stack */ public class DecoratorTest { public static void main(String[] args) { // Clean the wall WallBeautify wallBeautifyClean = new WallBeautifyClean(); wallBeautifyClean.operation(); System.out.println("--------------"); // Puttying WallBeautify wallBeautifyPutty = new WallBeautifyPutty(wallBeautifyClean); wallBeautifyPutty.operation(); System.out.println("--------------"); // Paint WallBeautify wallBeautifyPaint = new WallBeautifyPaint(wallBeautifyPutty); wallBeautifyPaint.operation(); System.out.println("--------------"); // Hanging murals WallBeautify wallBeautifyHang = new WallBeautifyHang(wallBeautifyPaint); wallBeautifyHang.operation(); System.out.println("--------------"); // Multilayer nesting WallBeautify wbh = new WallBeautifyHang(new WallBeautifyPaint( new WallBeautifyPutty(new WallBeautifyClean()))); wbh.operation(); System.out.println("--------------"); } }
All the actual combat source code of this tutorial has been uploaded to this warehouse:
https://github.com/javastacks/javastack
Output result:
Start cleaning the wall -------------- Start cleaning the wall Start puttying -------------- Start cleaning the wall Start puttying Start painting -------------- Start cleaning the wall Start puttying Start painting Start hanging murals -------------- Start cleaning the wall Start puttying Start painting Start hanging murals --------------
The result output is normal!
It can be seen that the use of decorator mode is relatively simple. Using decorator mode can achieve different decorative effects, which can meet the needs of different customers without changing the original code.
Follow up the series of design patterns in the official account Java technology stack, and keep your attention.
Application of decorator mode in JDK
Now we know how to use decorator mode. Now let's see where JDK uses decorator mode.
1. IO stream
The most classic application of decorator mode is IO stream in JDK (InputStream/ OutputStream)
The commonly used InputStream class structure classes are as follows:
InputStream and FileInputStream are basic component interfaces and implementations.
FilterInputStream is a decorator role that implements component interfaces and holds instance References:
BufferedInputStream and DataInputStream are decorative implementations of different FilterInputStream.
The same principle applies to OutputStream.
2. Synchronous collection
To simply provide thread safe functions for non thread safe collections (such as List and Set), it can also be easily realized by using decorator mode.
Take a look at the synchronization collection tool class methods:
java.util.Collections#synchronizedList(List)
java.util.Collections#synchronizedSet(Set)
They are decorator implementation classes of SynchronizedCollection:
SynchronizedCollection is the decorator role:
Synchronized Collection implements the Collection component interface and holds the Collection instance reference, while Collection (List) and ArrayList are the basic component interfaces and implementations.
summary
This paper introduces the basic concept of decorator mode, makes a basic practice, and gives two examples of decorator mode in JDK. I believe you have a basic understanding of decorator mode. How to apply it to the project, should you have a spectrum?
Of course, the design mode is only a reference for everyone to design, and can not be used blindly, otherwise it will backfire. In other words, how did you apply the decorator pattern in the project? Welcome to leave a message and share the case!
All the actual combat source code of this tutorial has been uploaded to this warehouse:
https://github.com/javastacks/javastack