【Java设计模式06】—— 装饰者模式

1 定义

装饰者模式:装饰者模式是以对客户端透明的方式动态地将责任附加到对象上,已达到扩展对象功能的目的。

如果要扩展对象的功能,装饰者模式提供了比继承更有弹性的替代方案。

装饰者模式的职责

  • 动态地为一个对象增加新的功能。
  • 装饰者模式是一种用于代替继承的技术,无须通过继承增加子类就能扩展对象的新功能。使用对象的关联关系代替继承关系,更加灵活,同时避免类型体系的快速膨胀。

2 类图

【Java设计模式06】—— 装饰者模式_第1张图片

  • Component接口:装饰者和被装饰对象都要实现共同的抽象接口。
  • ConcreteComponent被装饰者:这是装饰者将要去装饰的真实对象,装饰者将附加责任赋予该对象。
  • Decorator装饰者公共的抽象类:持有被装饰对象的引用,然后在真实对象调用前后增加新的功能。
  • ConcreteDecoratorA:具体的装饰者对象,分别有各自功能的实现。

3 例子

对于煎饼,我们可以通过加蛋、加肠来装饰它!

ICake饼接口:

/**
 * 饼接口:装饰者和被装饰者都要实现这个接口
 */
public interface ICake {

    /**
     * 描述
     */
    String description();

    /**
     * 价格
     */
    double price();
}

Pancake被装饰者:

/**
 * 煎饼
 * 被装饰者
 */
public class Pancake implements ICake {

    @Override
    public String description() {
        return "原味煎饼";
    }

    @Override
    public double price() {
        return 5.0;
    }
}

AbstractCakeDecorator装饰者抽象父类:

/**
 * 装饰者抽象父类
 */
public abstract class AbstractCakeDecorator implements ICake {

    /**
     * 持有被装饰者的引用
     */
    private ICake pancake;

    public AbstractCakeDecorator(ICake pancake) {
        this.pancake = pancake;
    }

    public ICake getPancake() {
        return pancake;
    }

    /**
     * 由子类实现
     */
    @Override
    public String description() {
        return "";
    }

    /**
     * 由子类实现
     */
    @Override
    public double price() {
        return 0;
    }
}

EggPancake装饰者1:

/**
 * 加鸡蛋的煎饼
 * 具体的装饰者之一
 */
public class EggPancake extends AbstractCakeDecorator {

    public EggPancake(ICake pancake) {
        super(pancake);
    }

    @Override
    public String description() {
        return getPancake().description() + " + 蛋";
    }

    @Override
    public double price() {
        return getPancake().price() + 2.0;
    }
}

SausagePancake装饰者2:

/**
 * 加肠的煎饼
 * 具体的装饰者之一
 */
public class SausagePancake extends AbstractCakeDecorator {

    public SausagePancake(ICake pancake) {
        super(pancake);
    }

    @Override
    public String description() {
        return getPancake().description() + " + 肠";
    }

    @Override
    public double price() {
        return getPancake().price() + 2.5;
    }
}

Client客户:

/**
 * 客户
 */
public class Client {

    public static void main(String[] args) {
        
        Pancake pancake = new Pancake();
        System.out.println(pancake.description());
        System.out.println("总价:" + pancake.price() + " 元");

        EggPancake eggPancake = new EggPancake(pancake);
        System.out.println(eggPancake.description());
        System.out.println("总价:" + eggPancake.price() + " 元");

        SausagePancake sausagePancake = new SausagePancake(eggPancake);
        System.out.println(sausagePancake.description());
        System.out.println("总价:" + sausagePancake.price() + " 元");
    }
}

输出:

原味煎饼
总价:5.0 元
原味煎饼 + 蛋
总价:7.0 元
原味煎饼 + 蛋 + 肠
总价:9.5 元

Process finished with exit code 0

由此可知,使用装饰者模式就不用创建大量新的类而可以拓展出具有更多功能的对象了。

4 装饰者模式在Java I/O库中的应用

IO流实现细节:

  • Component抽象构件角色:io流中的InputStream、OutputStream、Reader、Writer
  • ConcreteComponent具体构件角色:io流中的FileInputStream、FileOutputStream
  • Decorate装饰角色:持有抽象构件的引用,FilterInputStream、FilterOutputStream
  • ConcreteDecorate具体装饰角色:负责给构件对象添加新的责任,BufferedInputStream、BufferedOutputStream等

优点

(1)扩展对象功能,比继承灵活,不会导致类个数急剧增加。

(2)可以对一个对象进行多次装饰,创造出不同行为的组合,得到功能更加强大的对象。

(3)具体构 件 类和具体装饰类可以独立变化,用户可以根据需要自己增加新的 具体构件子类和具体装饰子类。

缺点

(1)产生很多小对象。大量小的对象占据内存,一定程度上影响性能。

(2)装饰模式易出错,调试排查比较麻烦。

你可能感兴趣的:(JAVA设计模式)