Design Pattern (8): Structural Decorator Pattern

Design Patterns Series Articles

Design Patterns (1): Creational Singleton Patterns

Design Patterns (2, 3): Creational Factory Methods and Abstract Factory Patterns

Design Patterns (4): Creational Prototype Patterns

Design Pattern (5): Creational Builder Pattern

Design Pattern (6): Structural Agent Pattern

Design Pattern (7): Structural Adapter Pattern

Design Pattern (8): Structural Decorator Pattern



1. Classification of Design Patterns

  • Creational patterns
    • Used to describe "how to create objects", its main feature is "separation of object creation and use"
    • Provides singletons, prototypes, factory methods, abstract factories, and builders 5 种创建型模式
  • structural pattern
    • Used to describe how to organize classes or objects into larger structures in a certain layout
    • Proxy, Adapter, Bridge, Decorator, Facade, Flyweight, Composition are provided 7 种结构型模式
  • behavioral model
    • Used to describe how classes or objects cooperate with each other to complete tasks that a single object cannot do alone, and how to assign responsibilities
    • Provides template methods, policies, commands, chain of responsibility, state, observers, mediators, iterators, visitors, mementos, interpreters 11 种行为型模式

2. Decorator mode

1 Overview

Let's start with an example of a fast food restaurant

  • Fast food restaurants serve fast food such as fried noodles and fried rice
  • Additional side dishes such as eggs, ham, and bacon can be added
  • Of course, adding side dishes requires extra money, and the price of each side dish is usually different
  • then 计算总价it will be more troublesome

Traditional way:

  • FastFood top-level food parent abstract object
  • FriedRice and FriedNoodles are the staple food and their prices
  • The bottom one is the staple food with different ingredients and the total price

insert image description here

Problems with using 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 subcategories
  • too many subclasses

Decorator pattern definition

Refers to the mode of dynamically adding some responsibilities (that is, adding additional functions) to the object without changing the structure of the existing object

2. Structure

Roles in Decorator mode:

  • Abstract component (Component) role: define an abstract interface to standardize the object ready to receive additional responsibilities
  • Concrete Component role: implement abstract components and add some responsibilities to them through decoration roles
  • Abstract decoration (Decorator) role: Inherit or implement abstract components, and contain instances of concrete components, and can extend the functions of concrete components through its subclasses
  • ConcreteDecorator role: implement related methods of abstract decoration, and add additional responsibilities to concrete component objects

3. Realize

  • Improvements to the fast food restaurant example using the decorator pattern
  • The class diagram is as follows:

insert image description here

code show as below:

  • Food abstract class
  • Both staple food and ingredients are its subcategories
@Data
@AllArgsConstructor
public abstract class FastFood {
    
    
    private float price;//价格
    private String desc; //描述
    public abstract float cost();//获取价格
}
  • Fried Rice and Fried Noodles
  • The construction method is to call the parent class construction method, assign the price and description
//炒饭
public class FriedRice extends FastFood {
    
    
	
    public FriedRice() {
    
    
        super(10, "炒饭");
    }

	@Override
    public float cost() {
    
    
        return getPrice();
    }
}

//炒面
public class FriedNoodles extends FastFood {
    
    

    public FriedNoodles() {
    
    
        super(12, "炒面");
    }
    
	@Override
    public float cost() {
    
    
        return getPrice();
    }
}
  • Ingredients abstract class
  • 聚合bring in the staple food
@Data
public abstract class Garnish extends FastFood {
    
    
    //声明快餐类的变量
    private FastFood fastFood;

    public Garnish(FastFood fastFood,float price, String desc) {
    
    
        super(price, desc);
        this.fastFood = fastFood;
    }
}
  • Ingredients
  • The construction method of the ingredients adds the staple food
  • Re-total price method: ingredient price + price of staple food aggregated in
  • Re-description method: staple food description + ingredient description
//鸡蛋配料
public class Egg extends Garnish {
    
    

    public Egg(FastFood fastFood) {
    
    
        super(fastFood,1,"鸡蛋");
    }

	@Override
    public float cost() {
    
    
        return getPrice() + getFastFood().getPrice();
    }

    @Override
    public String getDesc() {
    
    
        return super.getDesc() + getFastFood().getDesc();
    }
}

//培根配料
public class Bacon extends Garnish {
    
    

    public Bacon(FastFood fastFood) {
    
    
        super(fastFood,2,"培根");
    }

    @Override
    public float cost() {
    
    
        return getPrice() + getFastFood().getPrice();
    }

    @Override
    public String getDesc() {
    
    
        return super.getDesc() + getFastFood().getDesc();
    }
}
  • test class
public class Client {
    
    
    public static void main(String[] args) {
    
    
        //点一份炒饭
        FastFood food = new FriedRice();

        System.out.println(food.getDesc() + "  " + food.cost() + "元");

        System.out.println("===============");

        //在上面的炒饭中加一个鸡蛋
        food = new Egg(food);
        System.out.println(food.getDesc() + "  " + food.cost() + "元");

        System.out.println("================");
        //再加一个鸡蛋
        food = new Egg(food);
        System.out.println(food.getDesc() + "  " + food.cost() + "元");

        System.out.println("================");
        food = new Bacon(food);
        System.out.println(food.getDesc() + "  " + food.cost() + "元");
    }
}
  • The main principle is to inherit the food abstract class and aggregate the food abstract class
    • In the construction method of the ingredient class, the food abstract class needs to be aggregated
    • Then the generated food becomes the food category that the next ingredient can be aggregated into

4. JDK source code analysis

  • The wrapper class in the IO stream uses the decorator pattern
  • BufferedInputStream,BufferedOutputStream,BufferedReader,BufferedWriter

Take BufferedWriter as an example to illustrate

public class Demo {
    
    
    public static void main(String[] args) throws Exception{
    
    
        //创建BufferedWriter对象
        //创建FileWriter对象
        FileWriter fw = new FileWriter("C:\\Users\\Think\\Desktop\\a.txt");
        BufferedWriter bw = new BufferedWriter(fw);
        //写数据
        bw.write("hello Buffered");
        bw.close();
    }
}

It really feels like a decorator pattern to use, let's look at their structure:

insert image description here

  • The BufferedWriter class inherits Writer, aggregates Writer, and aggregates the constructor
  • The above example is aggregated into FileWriter fw
  • BufferedWriter rewrites write(char cbuf[], int off, int len), and the specific implementation is to call fw.write

summary:

BufferedWriter uses the decorator mode to enhance the Writer sub-implementation class, adding a buffer and improving the efficiency of writing data

5. The difference between proxy and decorator

Same point

  • must implement the same business interface as the target class
  • Declare the target object in both classes
  • can be done without modifying the target class增强目标方法

difference

  • different purpose
    • The decorator is to enhance the target object
    • Static proxy is to protect and hide the target object
  • different places to get target object build
    • The decorator is passed in from the outside world and can be passed through the constructor (aggregate the target object)
    • Static proxy is created inside the proxy class to hide the target object (combined target object)

Guess you like

Origin blog.csdn.net/qq_35512802/article/details/131094862