Basic introduction

I believe you can roughly guess the meaning of “decorator pattern” from the name, its core idea is to use some “decorations (classes)” to the original base class to wrap, so as to enhance or complete some specific functions.

Decorator mode allows you to attach new functionality to objects on the fly. And it is more flexible to extend objects using this pattern than simply through inheritance.

Core design UML class diagram:

From the UML class diagram above, you can see that the decorator pattern can be roughly divided into four roles:

Component: Can be an abstract class or interface, which is the top class of the class to be wrapped.

ConcreteComponent: A subclass of Component. ConcreteComponent is a concretely wrapped class.

Note: Sometimes there are many ConcreteComponent classes. For unified management, we can abstract different ConcreteComponent parent classes according to the characteristics of ConcreteComponent, and place them between The above Component and ConcreteComponent. That is, design a buffer layer between the two.

Decorator: This class inherits or implements Component and aggregates an object of the Component class in the class.

ConcreteDecorator: a subclass of Decorator, which is the ConcreteDecorator class that decorates the ConcreteComponent class.

A simple case

From the above class diagram and text description, we believe that you should have some basic understanding of the “decorator pattern”. Let’s use a small case to deepen the understanding of the design pattern.

Example: There is a beverage shop that has different flavors of drinks and different kinds of ingredients. Now we need an ordering system that can calculate the price of drinks that customers get through free matching.

Drinks => Component (Abstract Component)

public abstract class Drink {

  / / description
  private String describe;

  / / price
  private double price = 0.0;

  // An abstract way to calculate expenses
  public abstract double cost(a);

  / / the get () and set ()
}
Copy the code

Milk tea => ConcreteComponent

public class TeaWithMilk extends Drink {

  public TeaWithMilk(a) {
    setDescribe("Milk tea");
    setPrice(6.0);
  }

  @Override
  public double cost(a) {
    // Current price of milk tea
    returngetPrice(); }}Copy the code

Condiments => Decorator

public class Seasoning extends Drink {

  // Aggregate a Drink object, that is, the decorated object.
  private Drink drink;

  / / structure
  public Seasoning(Drink drink) {
    this.drink = drink;
  }

  @Override
  public double cost(a) {
    // The current condiment price plus the decorated object price.
    return getPrice() + drink.cost();
  }

  /** * Rewrite the getDescribe method to facilitate printing */
  @Override
  public String getDescribe(a) {
    return super.getDescribe() + "" + getPrice() + "+"+ drink.getDescribe(); }}Copy the code

ConcreteDecorator

/** ** */
public class Pearl extends Seasoning {

  / / structure
  public Pearl(Drink drink) {
    super(drink);
    setDescribe("Pearl");
    setPrice(2.5); }}/** ** ** */
public class Oats extends Seasoning {

  // constructor
  public Oats(Drink drink) {
    super(drink);
    setDescribe("Oats");
    setPrice(1.0); }}Copy the code

Client test classes

public class Client {

  // Order: one cup of milk tea + one oat + one pearl
  public static void main(String[] args) {
    // A cup of milk tea
    Drink drink = new TeaWithMilk();
    System.out.println("Payable:");
    System.out.println(drink.getDescribe() + drink.cost());

    // Add one serving of oats
    drink = new Oats(drink);
    System.out.println("An extra serving of oats will cost:");
    System.out.println(drink.getDescribe() + "In all:" + drink.cost());

    drink = new Pearl(drink);
    System.out.println("An additional portion of pearls will be paid for:");
    System.out.println(drink.getDescribe() + "In all:"+ drink.cost()); }}Copy the code

Execution Result:

So that’s all of the code for this case, which you might not understand at first when you look at it. Don’t panic, let me give you a little explanation, I believe you can be at a glance, understand the mystery.

In fact, this case uses the idea of recursive algorithms, and we can break it down.

Step 1: The customer ordered a milk tea.

Step 2: The customer orders an oatmeal on the basis of milk tea. At this point we need to decorate the milk tea in step 1 (see it as a whole) to get a milk tea with oats. Step 3: The client orders a pearl on the basis of milk tea with oats. What we need to decorate at this point is the milk tea with oats in the second step (consider it as a whole). Since then the whole order is complete, get a milk tea with oats and pearls (decoration complete).

Figure:This explanation makes the mystery clear.

conclusion

1, the use of decorator mode can be more flexible to expand the program, can be dynamically added with the needs of the business, can also be withdrawn when not needed, and through different decorators and decorators can derive different combinations.

2. Using decorator pattern to extend programs is OCP compliant.

3. Using decorator patterns also increases code complexity and, when overused, can spawn too many small classes, increasing system maintenance costs.

Any design pattern has its advantages and disadvantages, we should make reasonable use of design pattern in the right scene.

This is the end of today’s sharing. If you feel that the article written by “newbie” is still good, rememberLike and followYo! Your support is what keeps me going. Article where to write problems also hope that you can point out, I will be modestly taught.