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"