装饰模式Decorator

意图

      动态地给一个对象添加一些额外的职责。就增加功能来说, Decorator模式相比生成子类更为灵活。该模式以对客 户端透明的方式扩展对象的功能。

装饰模式的本质是动态组合。动态是手段,组合是目的。每个装饰类可以只负责添加一项额外功能,然后通过组合为被装饰类添加复杂功能。由于每个装饰类的职责比较简单单一,增加了这些装饰类的可重用性,同时也更符合单一职责原则。

适用环境

(1)在不影响其他对象的情况下,以动态、透明的方式给单个对象添加职责。

(2)处理那些可以撤消的职责。

(3)当不能采用生成子类的方法进行扩充时。一种情况是,可能有大量独立的扩展,为支持每一种组合将产生大量的 子类,使得子类数目呈爆炸性增长。另一种情况可能是因为类定义被隐藏,或类定义不能用于生成子类。

角色

    l 抽象构件(Component)角色:给出一个抽象接口,以规范准备接收附加责任的对象

    l 具体构件(ConcreteComponent)角色:定义一个将要接收附加责任的类

    l 装饰角色(Decorator):持有一个构件(Component)对象的实例,并定义一个与抽象构件接口一致的接口

    l 具体装饰角色(ConcreteDecorator):负责给构件对象“贴上”附加的责任

类图

实例

1抽象接口:

1.1饮料:

public interface Beverage {
    public String getDesc();

    public double getPrice();
}

2接口实现:

2.1奶茶:

public class Milktea implements Beverage {
    @Override
    public String getDesc() {
        System.out.println("--Milktea.desc");
        return "奶茶";
    }

    @Override
    public double getPrice() {
        System.out.println("--Milktea.price");
        return 10;
    }
}

2.2奶绿:

public class Milkgreen implements Beverage {
    @Override
    public String getDesc() {
        System.out.println("--Milkgreen.desc");
        return "奶绿";
    }

    @Override
    public double getPrice() {
        System.out.println("--Milkgreen.price");
        return 8;
    }
}

 3装饰类:装饰者类内有一个真实对象的引用

public class Decorator implements Beverage {

    private Beverage beverage = null;

    public Decorator(Beverage beverage) {
        System.out.println("--Decorator.construct");
        this.beverage = beverage;
    }

    @Override
    public String getDesc() {
        System.out.println("--Decorator.desc");
        return beverage.getDesc();
    }

    @Override
    public double getPrice() {
        System.out.println("--Decorator.price");
        return beverage.getPrice();//价格 子类决定
    }
}

 4继承装饰类(覆盖父类方法):

4.1红豆:

public class Redbean extends Decorator {
    private String desc = "加了红豆";

    public Redbean(Beverage beverage) {
        super(beverage);
    }

    public String getDesc() {
        System.out.println("--Redbean.desc");
        return super.getDesc() + desc + "的价钱:";
    }

    public double getPrice() {
        System.out.println("--Redbean.price");
        return super.getPrice() + 2;  //2表示红豆的价格
    }
}

4.2布丁:

public class Pudding extends Decorator {
    private String desc = "加了布丁";

    public Pudding(Beverage beverage) {
        super(beverage);
    }

    public String getDesc() {
        System.out.println("--Pudding.desc");
        return super.getDesc() + desc + "的价钱:";
    }

    public double getPrice() {
        System.out.println("--Pudding.price");
        return super.getPrice() + 1;//1表示布丁的价格
    }
}

5测试:

public class Test {
    public static void main(String[] args) {
        Beverage beverage = new Milktea();
        Redbean redbean = new Redbean(beverage);
        System.out.println(redbean.getDesc() + "
" + redbean.getPrice());
        Beverage rb = new Redbean(beverage);
        Beverage pb = new Pudding(rb);
        System.out.println(pb.getDesc() + "
" + pb.getPrice());//混合
    }
}

6结果:

--Decorator.construct
--Redbean.desc
--Decorator.desc
--Milktea.desc
--Redbean.price
--Decorator.price
--Milktea.price
奶茶加了红豆的价钱:
12.0
--Decorator.construct
--Decorator.construct
--Pudding.desc
--Decorator.desc
--Redbean.desc
--Decorator.desc
--Milktea.desc
--Pudding.price
--Decorator.price
--Redbean.price
--Decorator.price
--Milktea.price
奶茶加了红豆的价钱:加了布丁的价钱:
13.0

JDK运用

JDK中的装饰者模式:java.io

FilterInputStream继承(实现)InputStream,同时BufferedInputStream继承了FilterInputStream

  1. 抽象构件:最顶层的基类InputStream(饮料)
  2. 具体构件:FileInputStream和ObjectInputStream等(奶茶)
  3. 装饰角色:FilterInputStream中有一个InputStream的实例和构造方法传入InputStream对象(装饰器)
    public class FilterInputStream extends InputStream {
    
        protected volatile InputStream in;
    
        protected FilterInputStream(InputStream in) {
            this.in = in;
        }
  4. 具体装饰角色:BufferedInputStream中有构造方法传入InputStream对象,实现了装饰(红豆)
        public BufferedInputStream(InputStream in) {
            this(in, defaultBufferSize);
        }
    
        public BufferedInputStream(InputStream in, int size) {
            super(in);
            if (size <= 0) {
                throw new IllegalArgumentException("Buffer size <= 0");
            }
            buf = new byte[size];
        }

Head First 设计模式(中文版)的示例:

码云地址:https://gitee.com/manusas/DecoratorDP

原文地址:https://www.cnblogs.com/manusas/p/6722964.html