当前位置:网站首页>Interesting talk about decorator mode, so you will never forget it

Interesting talk about decorator mode, so you will never forget it

2022-06-24 02:22:00 Tom bomb architecture

This article is excerpted from 《 This is how design patterns should be learned 》

1 Use decorator mode to solve the problem of pancake overweight

Look at a scene like this , Most office workers have the habit of sleeping in , I have a tight time at work every morning , So many people want to sleep more , Just solve the breakfast problem in a more convenient way , Some people may have pancakes for breakfast . Eggs can be added to pancakes , Or sausages , But no matter how big it is , It's still a pancake . Another example , Add some fruit to the cake , Decorate the house , It's all decorator mode .

The following code is used to simulate the business scenario of adding code to pancakes , Let's look at the situation without decorator mode . First create a pancake Battercake class .

public class Battercake {

    protected String getMsg(){
        return " pancakes ";
    }

    public int getPrice(){
        return 5;
    }

}

Then create a pancake with eggs BattercakeWithEgg class .

public class BattercakeWithEgg extends Battercake{
    @Override
    protected String getMsg() {
        return super.getMsg() + "+1 An egg ";
    }

    @Override
    // Add 1 An egg with 1 Yuan 
    public int getPrice() {
        return super.getPrice() + 1;
    }
}

And create an egg and sausage BattercakeWithEggAndSausage class .

public class BattercakeWithEggAndSausage extends BattercakeWithEgg{
    @Override
    protected String getMsg() {
        return super.getMsg() + "+1 Sausages ";
    }

    @Override
    // Add 1 A sausage with 2 Yuan 
    public int getPrice() {
        return super.getPrice() + 2;
    }
}

Finally, write client test code .

public static void main(String[] args) {

        Battercake battercake = new Battercake();
        System.out.println(battercake.getMsg() + ", Total price :" + battercake.getPrice());

        Battercake battercakeWithEgg = new BattercakeWithEgg();
        System.out.println(battercakeWithEgg.getMsg() + ", Total price :" + 
			battercakeWithEgg.getPrice());

        Battercake battercakeWithEggAndSausage = new BattercakeWithEggAndSausage();
        System.out.println(battercakeWithEggAndSausage.getMsg() + ", Total price :" + 
			battercakeWithEggAndSausage.getPrice());

    }
		

The results are shown in the following figure .

image.png

There's no problem with the results . however , If the user needs a plus 2 An egg and 1 Pancakes with sausage , You can't create a class structure with the current class structure , The price can't be calculated automatically , Unless you create another class to customize . If the demand changes again , So it's obviously unscientific to add customization all the time .

Let's use decorator mode to solve the above problem . First create an abstract of the pancake Battercake class .

public abstract class Battercake {
    protected abstract String getMsg();
    protected abstract int getPrice();
}

Create a basic pancake ( Or basic package )BaseBattercake.

public class BaseBattercake extends Battercake {
    protected String getMsg(){
        return " pancakes ";
    }

    public int getPrice(){ return 5;  }
}

Then create an abstract decorator that extends the package BattercakeDecotator class .

public abstract class BattercakeDecorator extends Battercake {
    // Static proxy , delegate 
    private Battercake battercake;

    public BattercakeDecorator(Battercake battercake) {
        this.battercake = battercake;
    }
    protected abstract void doSomething();

    @Override
    protected String getMsg() {
        return this.battercake.getMsg();
    }
    @Override
    protected int getPrice() {
        return this.battercake.getPrice();
    }
}

Then create an egg decorator EggDecorator class .

public class EggDecorator extends BattercakeDecorator {
    public EggDecorator(Battercake battercake) {
        super(battercake);
    }

    protected void doSomething() {}

    @Override
    protected String getMsg() {
        return super.getMsg() + "+1 An egg ";
    }

    @Override
    protected int getPrice() {
        return super.getPrice() + 1;
    }
}

Create sausage decorators SausageDecorator class .

public class SausageDecorator extends BattercakeDecorator {
    public SausageDecorator(Battercake battercake) {
        super(battercake);
    }

    protected void doSomething() {}

    @Override
    protected String getMsg() {
        return super.getMsg() + "+1 Sausages ";
    }
    @Override
    protected int getPrice() {
        return super.getPrice() + 2;
    }
}

Then write the client test code .

public class BattercakeTest {
    public static void main(String[] args) {
        Battercake battercake;
        // Buy a pancake 
        battercake = new BaseBattercake();
        // Pancakes are a little small , Want to add more 1 An egg 
        battercake = new EggDecorator(battercake);
        // add 1 An egg 
        battercake = new EggDecorator(battercake);
        // Very hungry , add 1 Sausages 
        battercake = new SausageDecorator(battercake);

        // The biggest difference from static agents is that they have different responsibilities 
        // Static proxies don't have to satisfy is-a The relationship between 
        // Static agents will be enhanced , The same responsibility becomes different 

        // Decorators are more concerned with expansion 
        System.out.println(battercake.getMsg() + ", The total price :" + battercake.getPrice());
    }
}

The results are shown in the following figure .

image.png

Finally, let's look at the class diagram , As shown in the figure below .

image.png

2 Use decorator mode to extend log format output

To impress , Let's look at another application scenario . The demand is roughly like this , The system uses SLS Service monitoring project log , With JSON Format parsing , Therefore, you need to encapsulate the logs in the project into JSON Format and print . The existing log system adopts Log4j + Slf4j It's made of frames . The client invocation is as follows .

  private static final Logger logger = LoggerFactory.getLogger(Component.class);
        logger.error(string);
				

This prints out a random line of strings . When considering converting it into JSON When the format , The author adopts the decorator mode . At present, there are unified interfaces Logger And its concrete implementation class , What I want to add is a decorative class and really encapsulated into JSON Decorative products in format . Create decorator class DecoratorLogger.

public class DecoratorLogger implements Logger {

    public Logger logger;

    public DecoratorLogger(Logger logger) {

        this.logger = logger;
    }

    public void error(String str) {}

    public void error(String s, Object o) {

    }
    // Omit other default implementations 
}

Create specific components JsonLogger class .

public class JsonLogger extends DecoratorLogger {
    public JsonLogger(Logger logger) {
        super(logger);
    }
        
    @Override
    public void info(String msg) {

        JSONObject result = composeBasicJsonResult();
        result.put("MESSAGE", msg);
        logger.info(result.toString());
    }
    
    @Override
    public void error(String msg) {
        
        JSONObject result = composeBasicJsonResult();
        result.put("MESSAGE", msg);
        logger.error(result.toString());
    }
    
    public void error(Exception e) {

        JSONObject result = composeBasicJsonResult();
        result.put("EXCEPTION", e.getClass().getName());
        String exceptionStackTrace = Arrays.toString(e.getStackTrace());
        result.put("STACKTRACE", exceptionStackTrace);
        logger.error(result.toString());
    }
    
    private JSONObject composeBasicJsonResult() {
        // Assembled some runtime information 
        return new JSONObject();
    }
}

You can see , stay JsonLogger in , about Logger All kinds of interfaces , We all use JsonObject Object to a layer of encapsulation . When printing , Finally, call the native interface logger.error(string), Just this String The parameters have been decorated . If there is additional demand , You can write another function to implement . such as error(Exception e), Only one exception object is passed in , This is very convenient when calling .

in addition , In order to try not to change too much code and usage in the process of replacing the old with the new , The author is JsonLogger An internal factory class is added to the JsonLoggerFactory( This class is transferred to DecoratorLogger Maybe it's better ). It contains a static method , Used to provide the corresponding JsonLogger example . Finally, in the new log system , Use as follows .

    private static final Logger logger = JsonLoggerFactory.getLogger(Client.class);

    public static void main(String[] args) {

        logger.error(" error message ");
    }
		

For clients , The only difference from the original is that it will LoggerFactory Change it to JsonLoggerFactory that will do , Such an implementation , It will also be accepted and used by other developers faster and more easily . Finally, look at the class diagram shown in the figure below .

image.png

The most essential feature of the decorator pattern is to pull out the additional functions of the original class , Simplify the logic of the original class . Through these two cases , We can sum it up , In fact, abstract decorators are dispensable , You can choose according to the business model .

Pay attention to WeChat public number 『 Tom Bomb architecture 』 reply “ Design patterns ” The complete source code is available .

【 recommend 】Tom Bomb architecture :30 A real case of design pattern ( Source code attached ), Challenge annual salary 60W Is not a dream

This paper is about “Tom Bomb architecture ” original , Reprint please indicate the source . Technology is about sharing , I share my happiness ! If this article helps you , Welcome to pay attention and like ; If you have any suggestions, you can also leave comments or private letters , Your support is the driving force for me to adhere to my creation . Pay attention to WeChat public number 『 Tom Bomb architecture 』 More technical dry goods are available !

原网站

版权声明
本文为[Tom bomb architecture]所创,转载请带上原文链接,感谢
https://yzsam.com/2021/11/20211101194705388H.html

随机推荐