Decorator mode
1. Basic knowledge
Definition:
Function is added to the object without changing the original object
Provides a more flexible alternative than inheritance (extending the original object function)
Type: structural type
Through the construction method, the subclass is passed in, the subclass is wrapped, the base subclass object is received with the parent class in the decorator class, and the parent class object is returned, which can achieve unlimited packaging
Applicable scenario
Extend the functionality of a class or add additional responsibilities to a class
Dynamically add functions to an object, and these functions can be dynamically revoked
advantage
Inheritance is a powerful supplement, which is more flexible than inheritance, and extends the function of an object without changing the original object
Different effects can be achieved by using different decorative classes and the arrangement and combination of these decorative classes
Comply with the opening and closing principle
shortcoming
There will be more code, more classes and more program complexity
In dynamic decoration, multi-layer decoration will be more complex
Related design patterns
Decorator mode and agent mode
Decorator mode and adapter mode
2. Actual combat
Let's take milk tea as an example. A single cup of milk tea costs 8 yuan. One coconut is 2 yuan and one pudding is 3 yuan. I want to add two coconut and one pudding.
UML is shown in the figure below:
/** * Milk tea decorator class, an abstract class that combines milk tea in a class */ public abstract class AbstractDecorator extends ATeaMilk { //Inherit an abstract class and assemble the abstract object private ATeaMilk aTeaMilk; public AbstractDecorator(ATeaMilk aTeaMilk) { this.aTeaMilk = aTeaMilk; } protected abstract void doSomething(); @Override protected String getDesc() { return this.aTeaMilk.getDesc(); } @Override protected int cost() { return this.aTeaMilk.cost(); } }
/** * Milk tea base * @Author LYS * @Date 2022/1/18 16:38 * @Version 1.0 */ public abstract class ATeaMilk { protected abstract String getDesc(); protected abstract int cost(); }
/** * Coconut decoration, 1 share, 2 yuan * * @Author LYS * @Date 2022/1/18 16:41 * @Version 1.0 */ public class CoconutDecorator extends AbstractDecorator { public CoconutDecorator(ATeaMilk aTeaMilk) { super(aTeaMilk); } @Override protected void doSomething() { } @Override protected String getDesc() { return super.getDesc() + " Add a coconut and 2 pieces"; } //A coconut is 2 yuan @Override protected int cost() { return super.cost() + 2; } }
/** * Pudding 3 yuan a pudding * @Author LYS * @Date 2022/1/18 16:44 * @Version 1.0 */ public class PuddingDecorator extends AbstractDecorator{ public PuddingDecorator(ATeaMilk aTeaMilk) { super(aTeaMilk); } @Override protected void doSomething() { } @Override protected String getDesc() { return super.getDesc() + " Add a pudding for 3 yuan"; } //A pudding costs 3 yuan @Override protected int cost() { return super.cost() + 3; } }
/** * @Author LYS * @Date 2022/1/18 16:40 * @Version 1.0 */ public class TeaMike extends ATeaMilk { @Override protected String getDesc() { return "Milk tea 8 pieces"; } //Milk tea defaults to 8 yuan a cup @Override protected int cost() { return 8; } }
public class Test { public static void main(String[] args) { //ATeaMilk is an abstract class of all classes ATeaMilk aTeaMilk; //TeaMike is the implementation class of ATeaMilk. It defines a cup of ordinary milk tea. The definition method cost is 8 aTeaMilk = new TeaMike(); //CoconutDecorator(); The implementation class definition method cost passed into the ATeaMilk base class is super cost()+2; That is, 8 + 2 returns the ATeaMilk object aTeaMilk = new CoconutDecorator(aTeaMilk); aTeaMilk = new CoconutDecorator(aTeaMilk); //PuddingDecorator(); The implementation class definition method cost passed into the ATeaMilk base class is super cost()+3; That is, 8 + 3 returns the ATeaMilk object aTeaMilk = new PuddingDecorator(aTeaMilk); //The cost() method is called here. It should be that the current aTeaMilk has been wrapped in several layers. This call is called continuously in and out of the stack System.out.println(aTeaMilk.getDesc() + " selling price:" + aTeaMilk.cost()); } }
3. Source code
java io
There are many ways to add cache classes
BufferedReader class inherits reader. Combined reader is a decorator class, which can inherit subclasses of reader indefinitely, similar to milk tea class in practice
public class BufferedReader extends Reader { private Reader in; public BufferedReader(Reader in, int sz) { super(in); if (sz <= 0) throw new IllegalArgumentException("Buffer size <= 0"); this.in = in; cb = new char[sz]; nextChar = nChars = 0; }
FilterInputStream inherits InputStream, and InputStream in is assembled in the class
class FilterInputStream extends InputStream { /** * The input stream to be filtered. */ protected volatile InputStream in;
TransactionAwareCacheDecorator in spring handles Cache and synchronization transactions. This class is the decorator class of Cache
public class TransactionAwareCacheDecorator implements Cache { private final Cache targetCache; public TransactionAwareCacheDecorator(Cache targetCache) { Assert.notNull(targetCache, "Target Cache must not be null"); this.targetCache = targetCache; }
wrapper ends in either decorator mode or adapter mode, depending on the inheritance implementation structure of the specific class
In mybatis