Design pattern Decorator Pattern

Decorator mode

Definition
On the basis of not changing the original object, the function is attached to the original function to expand the function.
The decorator pattern provides a more flexible alternative to inheritance.

type
Structural type.

Applicable scenario

  • Extend the functionality of a class or add additional responsibilities to a class.
  • Add responsibilities to individual objects in a dynamic and transparent manner without affecting other objects.
  • You need to add functions to an object dynamically, and these functions can also be revoked dynamically.

Advantage

  • Different effects can be achieved by using different decoration classes and the arrangement and combination of these classes.
  • Comply with the opening and closing principle.
  • The purpose of decorator pattern and inheritance relationship is to extend the function of the original object, but decorator pattern can provide more flexibility than inheritance.

shortcoming

  • More code, more classes, more complexity.
  • Dynamic decoration and multi-layer decoration will make the system more complex.
  • The more flexible it is, the more error prone it is.

Relevant design patterns

  • Decorator mode and agent mode: decorator mode focuses on the dynamic addition of object functions. The agent mode focuses on controlling access to objects and hiding specific information of objects from its users.

  • Decorator pattern and adapter pattern: the decorator pattern and the decorated class should implement the same interface, or the decorated class is a subclass of the decorated class. The adapter pattern and the class to be adapted have different interfaces.

Example
Here is an example of pancakes. People usually add something to pancakes, such as eggs, sausages, etc.
Let's first look at the example implemented by normal inheritance.
Battercake class, pancake class.

package com.kaven.design.pattern.structural.decorator;

public class Battercake {
    protected String getDesc(){
        return "A pancake";
    }
    protected int cost(){
        return 8;
    }
}

BattercakeWithEgg class, pancake class with eggs, inherits the Battercake class.

package com.kaven.design.pattern.structural.decorator;

public class BattercakeWithEgg extends Battercake {

    public String getDesc() {
        return super.getDesc()+" Add an egg";
    }

    public int cost() {
        return super.cost()+1;
    }
}

Battercakewithsauce class, pancake class with sausage, inherits Battercake class.

package com.kaven.design.pattern.structural.decorator;

public class BattercakeWithSausage extends BattercakeWithEgg {
    @Override
    public String getDesc() {
        return super.getDesc()+" Add a sausage";
    }

    @Override
    public int cost() {
        return super.cost()+2;
    }
}

Application layer code:

package com.kaven.design.pattern.structural.decorator;

public class Test {
    public static void main(String[] args) {
        Battercake battercake = new Battercake();
        System.out.println(battercake.getDesc()+" selling price:"+battercake.cost());

        BattercakeWithEgg battercakeWithEgg = new BattercakeWithEgg();
        System.out.println(battercakeWithEgg.getDesc()+" selling price:"+battercakeWithEgg.cost());

        BattercakeWithSausage battercakeWithSausage = new BattercakeWithSausage();
        System.out.println(battercakeWithSausage.getDesc()+" selling price:"
                + battercakeWithSausage.cost());

    }
}

Output:

Pancake sales price: 8
 Pancakes and an egg sales price: 9
 Pancakes with an egg and a sausage selling price: 11

What if I need pancakes with two eggs and two sausages?
At this point, we need to implement another class to meet the requirements, but such requirements are diverse. Obviously, it is not good to implement this example with the method of common inheritance.

Improvement
ABattercake class, abstract pancake class.

package com.kaven.design.pattern.structural.decorator.v2;

public abstract class ABattercake {
    protected abstract String getDesc();
    protected abstract int cost();
}

Battercake class, concrete pancake class, inherits the ABattercake class.

package com.kaven.design.pattern.structural.decorator.v2;

public class Battercake extends ABattercake {

    protected String getDesc() {
        return "A pancake";
    }

    protected int cost() {
        return 8;
    }
}

AbstractDecorator class, abstract decorator class, inherits ABattercake class.

package com.kaven.design.pattern.structural.decorator.v2;

//Judge whether the abstract decorator should be defined as an abstract class according to the business
public class AbstractDecorator extends ABattercake {
    private ABattercake aBattercake;

    public AbstractDecorator(ABattercake aBattercake) {
        this.aBattercake = aBattercake;
    }

    protected String getDesc() {
        return this.aBattercake.getDesc();
    }

    protected int cost() {
        return this.aBattercake.cost();
    }
}

EggDecorator class, which implements the specific decorator of egg business, inherits AbstractDecorator class.

package com.kaven.design.pattern.structural.decorator.v2;

public class EggDecorator extends AbstractDecorator {
    public EggDecorator(ABattercake aBattercake) {
        super(aBattercake);
    }

    @Override
    protected String getDesc() {
        return super.getDesc()+" Add an egg";
    }

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

The SausageDecorator class implements the specific decorator of sausage business and inherits the AbstractDecorator class.

package com.kaven.design.pattern.structural.decorator.v2;

public class SausageDecorator extends AbstractDecorator{

    public SausageDecorator(ABattercake aBattercake) {
        super(aBattercake);
    }

    @Override
    protected String getDesc() {
        return super.getDesc()+" Add a sausage";
    }

    @Override
    protected int cost() {
        return super.cost()+2;
    }
}

Application layer code:

package com.kaven.design.pattern.structural.decorator.v2;

public class Test {
    public static void main(String[] args) {
        ABattercake aBattercake;
        aBattercake = new Battercake();
        aBattercake = new EggDecorator(aBattercake);
        aBattercake = new EggDecorator(aBattercake);
        aBattercake = new SausageDecorator(aBattercake);

        System.out.println(aBattercake.getDesc()+" selling price:"+aBattercake.cost());
    }
}

Output:

Pancakes and an egg and an egg and a sausage selling price: 12

A simple decorator pattern example is completed. Is this method easier to expand than the previous method? You can add a few eggs and a few sausages without adding classes. If you can add bacon to pancakes, you just need to add a specific decorator of bacon business.

If there's something wrong, please don't hesitate to comment.

256 original articles published, 158 praised, 310000 visitors+
His message board follow

Posted by erock on Sun, 26 Jan 2020 01:29:26 -0800