“This is the 16th day of my participation in the Gwen Challenge in November. Check out the details: The Last Gwen Challenge in 2021.”

1. Overview of decorator pattern

background

Some people find a convenient way to get more sleep in the morning. Some people may have pancakes for breakfast. Pancakes can be made with eggs or sausage, but no matter how “extra” they are, they are still pancakes. In real life, it is often necessary to add new functions or beautify the appearance of existing products, such as house decoration, photo and frame, coffee and seasoning, etc., which are all decorators.

Definition of decorator pattern

Definition of Decorator pattern: A pattern that dynamically adds some responsibility (additional functionality) to an existing object without changing its structure.

Decorator pattern belongs to object structure pattern and also embodies the open closed principle (OCP).

Advantages and disadvantages of decorator pattern

Advantages:

  • Decorators are a powerful complement to inheritance and are more flexible than inheritance, dynamically extending functionality to an object without changing the original object, plug and play
  • Different effects can be achieved by using different decorative classes and permutations of these decorative classes
  • Decorator mode fully follows the open and closed principle

Disadvantages: Decorator mode can add many subclasses, overuse can add complexity to the program.

2. Decorator pattern structure

Decorator pattern structure

The decorator pattern mainly contains the following roles.

  1. Abstract Component Role: Defines an abstract interface to specify objects that are ready to receive additional responsibilities.
  2. ConcreteComponent roles: Implement abstract artifacts, adding responsibilities to them by decorating them.
  3. Decorator role: Inherits an abstract artifact and contains instances of a concrete artifact that can be subclassed to extend its functionality.
  4. The ConcreteDecorator role: Implements methods associated with abstract decorators and adds additional responsibilities to concrete component objects.

Schematic of decorator pattern

3. Realization of decorator mode

Place orders of Starbucks coffee + condiments and calculate expenses

Define Abstract Component Roles: Define an abstract interface to specify objects that are ready to receive additional responsibilities.

public abstract class Drink {

    public String dsc; / / description
    private float price = 0.0 f; / / price

    public String getDsc(a) {
        return dsc;
    }

    public void setDsc(String dsc) {
        this.dsc = dsc;
    }

    public float getPrice(a) {
        return price;
    }

    public void setPrice(float price) {
        this.price = price;
    }

    // An abstract method for calculating costs, implemented by subclasses
    public abstract float cost(a);

}
Copy the code

Define ConcreteComponent roles: Implement abstract roles, adding responsibilities to them by decorating them.

public class Coffee extends Drink{
    @Override
    public float cost(a) {
        return super.getPrice(); }}Copy the code

ConcreteComponent role 1: Espresso

public class Espresso extends Coffee{

    public Espresso(a){
        setDsc("Italian coffee");
        setPrice(10.0 f); }}Copy the code

ConcreteComponent character 2: LongBlack Americano 1

public class LongBlack extends Coffee{
    
    public LongBlack(a){
        setDsc("Americano 1");
        setPrice(9.0 f); }}Copy the code

ConcreteComponent character 3: LongBlack Americano 2

public class ShortBlack extends Coffee{
    
    public ShortBlack(a){
        setDsc("Americano 2");
        setPrice(8.0 f); }}Copy the code

Define the Abstract Decorator role: Inherits an abstract artifact and contains instances of the concrete artifact that can be subclassed to extend its functionality.

public class Decorator extends Drink{

    // Decorator combines abstract components (decorator)
    private Drink obj;

    public Decorator(Drink obj){
        this.obj = obj;
    }

    @Override
    public float cost(a) {
        // Calculate fees: parent fees + own fees
        return getPrice() + obj.getPrice();
    }

    @Override
    public String getDsc(a) {
        // Output description: description of the parent class + its own description
        return dsc + "" + getPrice() + ""+obj.getDsc(); }}Copy the code

Define ConcreteDecorator roles: Implement methods associated with abstract decorators and add additional responsibilities to concrete component objects.

ConcreteDecorator Character 1: Chocolate Chocolate

public class Chocolate extends Decorator{

    public Chocolate(Drink obj) {
        super(obj);
        setDsc("Chocolate");
        setPrice(3.0 f); }}Copy the code

ConcreteDecorator character 2: Milk

public class Milk extends Decorator{
    
    public Milk(Drink obj) {
        super(obj);
        setDsc("Milk");
        setPrice(2.0 f); }}Copy the code

Role 3: Soy milk

public class Soy extends Decorator{
    
    public Soy(Drink obj) {
        super(obj);
        setDsc("Soy milk");
        setPrice(1.5 f); }}Copy the code

Write test class to place coffee order, test decorator pattern:

public class coffeeBar {
    public static void main(String[] args) {

        // An American
        Drink order1 = new LongBlack();
        System.out.println("Order Description:" + order1.getDsc());
        System.out.println("Order cost =" + order1.cost());

        // One American and one milk
        order1 = new Milk(order1);
        System.out.println("Order Description:" + order1.getDsc());
        System.out.println("Order cost =" + order1.cost());

        // One American + 2 milk
        order1 = new Milk(order1);
        System.out.println("Order Description:" + order1.getDsc());
        System.out.println("Order cost =" + order1.cost());

        // One American cup + 2 milk + chocolate
        order1 = new Chocolate(order1);
        System.out.println("Order Description:" + order1.getDsc());
        System.out.println("Order cost ="+ order1.cost()); }}Copy the code

4. Application scenarios of decorator mode

Application scenario of decorator pattern

  • When additional responsibilities need to be added to an existing class that cannot be extended by subclassing. For example, if the class is hidden or the class is the ultimate class or inherits a large number of subclasses.
  • Inheritance is difficult to implement when you need to produce a lot of functionality by permutations and combinations of an existing set of basic functionality, and decorator patterns are fine.
  • When the functional requirements of an object can be dynamically added or removed.

The decorator pattern is embodied in Java

The most famous use of the decorator pattern in the Java language is the design of the Java I/O standard library. For example, InputStream subclass FilterInputStream, OutputStream subclass FilterOutputStream, Reader subclass BufferedReader and FilterReader, There are subclasses of Writer, BufferedWriter, FilterWriter, PrintWriter, etc., which are abstract decorator classes.