Complete notes Directory: Contents of notes on detailed explanation of design pattern , welcome advice!
Structural mode describes how to form a larger structure of classes or objects according to a certain layout. There are two types:
- Class structured pattern: uses inheritance mechanism to organize interfaces and classes.
- Object structured pattern: use combination or aggregation to combine objects.
Because the coupling degree of composite relationship or aggregation relationship is lower than that of inheritance relationship and meets the "composite Reuse Principle", the object structured pattern has more flexibility than the class structured pattern.
The structural mode is divided into the following 7 types:
- proxy pattern
- Adapter mode
- Decorator mode
- Bridging mode
- Appearance mode
- Combination mode
- Sharing mode
5.3 decorator mode
5.3.1 general
Let's take an example of a fast food restaurant: fast food restaurants have fried noodles, fried rice and other fast food. They can add side dishes such as eggs, ham and bacon. Of course, adding side dishes requires additional money. The price of each side dish is usually different, so it will be more troublesome to calculate the total price. The following is a class diagram using inheritance:
Problems with inheritance:
- Poor scalability: if we want to add another ingredient (ham sausage), we will find that we need to define a subclass for FriedRice and FriedNoodles respectively. If you want to add a fast food category (fried rice noodles), you need to define more subclasses.
- Too many subclasses generated
**Decorator mode: * * a mode that dynamically adds some responsibilities (i.e. additional functions) to the object without changing the existing object structure.
5.3.2 structure
Roles in Decorator mode:
- Abstract Component role: define an abstract interface to standardize objects ready to receive additional responsibilities.
- Concrete Component role: implement abstract components and add some responsibilities to them by decorating roles.
- Abstract Decorator role: inherits or implements abstract components and contains instances of specific components. The functions of specific components can be extended through their subclasses.
- Concrete decorator role: implement relevant methods of abstract decoration and add additional responsibilities to specific component objects.
5.3.3 cases
The decorator mode is used to improve the fast food restaurant case. The class diagram is as follows:
Abstract component role: fast food class
@Data public abstract class FastFood { private float price; // Price private String desc; // describe public FastFood(float price, String desc) { this.price = price; this.desc = desc; } public abstract float cost(); }
Specific component roles: fried rice and fried noodles
public class FriedRice extends FastFood { public FriedRice() { super(10, "Fried rice"); } public float cost() { return getPrice(); } } public class FriedNoodles extends FastFood { public FriedNoodles() { super(12, "Stir-Fried Noodles with Vegetables"); } public float cost() { return getPrice(); } }
Abstract decorator role: ingredient class
@Data public abstract class Garnish extends FastFood { // Declare variables for fast food classes private FastFood fastFood; public Garnish(FastFood fastFood, float price, String desc) { super(price, desc); this.fastFood = fastFood; } }
Specific decorator roles: egg ingredients and bacon ingredients
public class Egg extends Garnish { public Egg(FastFood fastFood) { super(fastFood, 1, "egg"); } // Calculate price public float cost() { return getPrice() + getFastFood().cost(); } @Override public String getDesc() { return super.getDesc() + getFastFood().getDesc(); } } public class Bacon extends Garnish { public Bacon(FastFood fastFood) { super(fastFood, 2, "Bacon"); } // Calculate price public float cost() { return getPrice() + getFastFood().cost(); } @Override public String getDesc() { return super.getDesc() + getFastFood().getDesc(); } }
Test class:
public class Client { public static void main(String[] args) { // Order a fried rice FastFood food = new FriedRice(); System.out.println(food.getDesc() + " " + food.cost() + "element"); // Add an egg to the fried rice above food = new Egg(food); System.out.println(food.getDesc() + " " + food.cost() + "element"); // Add another egg food = new Egg(food); System.out.println(food.getDesc() + " " + food.cost() + "element"); // Add another bacon food = new Bacon(food); System.out.println(food.getDesc() + " " + food.cost() + "element"); } }
Fried rice 10.0 element Fried rice with eggs 11.0 element Fried rice with eggs 12.0 element Fried rice with bacon and eggs 14.0 element
5.3.4 usage scenarios
- When the system cannot be extended by inheritance or inheritance is not conducive to system expansion and maintenance.
There are two main types of situations in which inheritance cannot be used:
- The first is that there are a large number of independent extensions in the system. In order to support each combination, a large number of subclasses will be generated, resulting in an explosive increase in the number of subclasses.
- The second type is because the class definition cannot inherit (such as final class).
-
Add responsibilities to a single object in a dynamic and transparent manner without affecting other objects.
-
When the functional requirements of the object can be added dynamically or revoked dynamically.
5.3.5 JDK source code analysis
The wrapper class in the IO stream uses the decorator mode: BufferedInputStream, BufferedOutputStream, BufferedReader, BufferedWriter.
Take BufferedWriter as an example. Let's see how to use BufferedWriter:
// Create FileWriter object FileWriter fw = new FileWriter("C:\\Users\\Think\\Desktop\\a.txt"); // Create BufferedWriter object BufferedWriter bw = new BufferedWriter(fw); // Write data bw.write("hello Buffered"); bw.close();
It really feels like a decorator mode. Next, let's look at their structure:
BufferedWriter uses decorator mode to enhance the Writer subclass and add buffer to improve the efficiency of writing data.
5.3.6 difference between agent and decorator
Similarities:
- Must implement the same business interface as the target class
- Declare the target object in both classes
- Can enhance the target method without modifying the target class
difference:
-
Different purposes
The decorator is to enhance the target object
Static proxy is to protect and hide the target object
Decorators can be enhanced iteratively, and agents can only be enhanced once
- Getting the target object is built differently
The decorator is passed in from the outside, which can be passed through the construction method
Static proxy is created inside the proxy class to hide the target object