Design mode: decorator mode

Keywords: Java Design Pattern

In the future, I will update some documents on the introduction, application and principle of design patterns. If you think it's useful to yourself, pay attention.

introduction

The examples in this article are as simple as possible to avoid a lot of useless code in some examples when I usually check the data, which makes people feel unable to read

Decorator mode

  decorator mode: dynamically attach responsibilities to objects. To expand functionality, decorators provide more flexible alternatives than inheritance.
  after reading the above definition, in fact, it is converted into easy to understand words, that is, the enhancement of an object. At this moment, hearing this sentence, the little partner who understands (agent mode) calls me familiar with this business. In fact, the boundary between agent mode and decorator mode is very vague. Let's make a simple difference here.

  • Agent mode: mainly to enhance some non business functions, such as printing logs
  • Decorator mode: it is mainly the enhancement of business functions, such as adding the original business computing logic

Example

Suppose a case: you have a braised chicken store. At the beginning of the store, your family only sells braised chicken, and you can't add any side dishes, such as fish balls, rape, fish tofu, wide flour, potatoes, baby vegetables, kelp, dried tofu, tofu skin (it and dried tofu are two kinds of things in Northeast China), etc! So a kind of braised chicken came out.

package designpattern.decoratorpattern.components;

/**
 * @author: wangxu
 * @date: 2021-09-15 20:10
 */
public class YellowChicken {
    //Full name of this order
    private String allName = "Braised chicken";

    //Braised chicken price
    private Double price = 17.0;

    public String getYellowChickenName(){
        return allName;
    }

    public Double getYellowChickenPrice(){
        return price;
    }
}

  in this way, we only need to call getYellowChickenPrice() method every time we check out, but as a programmer, we should consider the problem of extension. If I join the side dish one day, we can do it. If the code is described as above, we can only use code instead

package designpattern.decoratorpattern.components;

/**
 * @author: wangxu
 * @date: 2021-09-15 20:10
 */
public class YellowChicken {
    //Full name of this order
    private String allName = "Braised chicken + Fish tofu";

    //Braised chicken price
    private Double price = 17.0 + 3.0;

    public String getYellowChickenName(){
        return allName;
    }

    public Double getYellowChickenPrice(){
        return price;
    }
}

  is that ok? This is obviously very inflexible. Besides, if I add spinach instead of fish tofu, do we have to change the code? We can't build a class for all the permutations and combinations of side dishes, so we need to use the decorator mode to make it more flexible and follow the "opening and closing principle". We can do this,
  first, let's abstract the code

package designpattern.decoratorpattern;

/**
 * @author: wangxu
 * @date: 2021-09-15 20:36
 */
public interface Food {
    public String getYellowChickenName();

    public Double getYellowChickenPrice();
}

  then let the braised chicken class implement this interface. Note that this class is the decorator

package designpattern.decoratorpattern.components;

import designpattern.decoratorpattern.Food;

/**
 * @author: wangxu
 * @date: 2021-09-15 20:10
 */
public class YellowChicken implements Food {
    //Full name of this order
    private String allName = "Braised chicken";

    //Braised chicken price
    private Double price = 17.0;
	
	//This is for the convenience of creating new products in the future. For example, green braised chicken and white braised chicken may be invented in the future
    public YellowChicken(String Name){
        this.allName = Name;
    }
    
    @Override
    public String getYellowChickenName(){
        return allName;
    }
    @Override
    public Double getYellowChickenPrice(){
        return price;
    }
}

OK! The key is to declare the decorator. The decorator should also implement this object to ensure that they belong to a type of object

package designpattern.decoratorpattern.decorater;

import designpattern.decoratorpattern.Food;

/**
 * @author: wangxu
 * @date: 2021-09-15 20:44
 */
public class Spinach implements Food {
    //Utilization combination
    Food food;

    //Full name of this order
    String allName = "rape";

    //Rape price
    Double price = 3.0;


    public Spinach(Food food){
        this.food = food;
    }
    @Override
    public String getYellowChickenName() {
        return food.getYellowChickenName() + allName;
    }

    @Override
    public Double getYellowChickenPrice() {
        return food.getYellowChickenPrice() + price;
    }
}

Another side dish

package designpattern.decoratorpattern.decorater;

import designpattern.decoratorpattern.Food;

/**
 * @author: wangxu
 * @date: 2021-09-15 20:44
 */
public class FishTofu implements Food {
    //Utilization combination
    Food food;

    //Full name of this order
    String allName = "Fish tofu";

    //Rape price
    Double price = 3.0;


    public FishTofu (Food food){
        this.food = food;
    }
    @Override
    public String getYellowChickenName() {
        return food.getYellowChickenName() + allName;
    }

    @Override
    public Double getYellowChickenPrice() {
        return food.getYellowChickenPrice() + price;
    }
}

If you don't understand it now, let's see how we can decorate a class

package designpattern.decoratorpattern;

import designpattern.decoratorpattern.components.Milk;
import designpattern.decoratorpattern.components.YellowChicken;
import designpattern.decoratorpattern.decorater.FishTofu;
import designpattern.decoratorpattern.decorater.Honey;
import designpattern.decoratorpattern.decorater.Spinach;
import designpattern.decoratorpattern.decorater.Sugar;

/**
 * @author: wangxu
 * @date: 2020/4/16 16:40
 */
public class Main {
    /*public static void main(String[] args) {
        //Test decorator mode
        //Create a new milk component
        Drink milk = new Milk();
        //Decorate him with sugar
        milk = new Sugar(milk);
        //Modify the combination of sugar and milk with honey (this is actually an expansion of function)
        milk = new Honey(milk);

        System.out.println("Price: "+ milk.cost() +" Name: "+ milk.getDrinkName());
    }*/

    public static void main(String[] args) {
        //Test decorator mode
        //Create a decorated person
        Food yellowChicken = new YellowChicken("Braised chicken");
        //Now let's check out
        Double yellowChickenPrice = yellowChicken.getYellowChickenPrice();
        String yellowChickenName = yellowChicken.getYellowChickenName();

        //Output name and price
        System.out.println("Basic braised chicken:" + yellowChickenPrice);
        System.out.println("Basic braised chicken:" + yellowChickenName);

        //Try to decorate him with rape
        yellowChicken = new Spinach(yellowChicken);
        //Checkout upgrade
        Double yellowChickenOnePrice = yellowChicken.getYellowChickenPrice();
        String yellowChickeOnenName = yellowChicken.getYellowChickenName();

        //Output the price of braised chicken version 1.0
        System.out.println("1.0 Braised chicken in brown sauce:" + yellowChickenOnePrice);
        System.out.println("1.0 Braised chicken in brown sauce:" + yellowChickeOnenName);

        //Upgrade again and add fish tofu
        yellowChicken = new FishTofu(yellowChicken);
        //Checkout version 2.0
        Double yellowChickenTwoPrice = yellowChicken.getYellowChickenPrice();
        String yellowChickeTwonName = yellowChicken.getYellowChickenName();

        //Output the price of braised chicken version 2.0
        System.out.println("2.0 Braised chicken in brown sauce:" + yellowChickenTwoPrice);
        System.out.println("2.0 Braised chicken in brown sauce:" + yellowChickeTwonName);

    }
}

Let's look at the results

Basic braised chicken:17.0
 Basic braised chicken:Braised chicken
1.0 Braised chicken in brown sauce:20.0
1.0 Braised chicken in brown sauce:Braised chicken-rape
2.0 Braised chicken in brown sauce:23.0
2.0 Braised chicken in brown sauce:Braised chicken-rape-Fish tofu

  see, every time we modify the last version, we expand its function. The most important thing is that it fully conforms to the opening and closing principle. If one day I want to add more ingredients, we just need to create a side dish class again, then implement the Food interface, and finally modify it with an appropriate modifier when it is used. This is a bit like the Creative Workshop in Steam. Every modification All of them are a MOD

Conclusion: Generally speaking, the modifier mode is not difficult. You can basically understand the code. In fact, it is the flexible application of combination. Finally, it is important to mention that you should try to follow the "opening and closing principle"

Posted by bw on Wed, 15 Sep 2021 15:49:29 -0700