java设计模式-装饰器模式

1.装饰器(Decorator)模式的定义

  • 指在不改变现有对象结构的情况下,动态地给该对象增加一些职责(即增加其额外功能)的模式,它属于对象结构型模式。

2.装饰器模式的主要优缺点

优点:

  • 采用装饰模式扩展对象的功能比采用继承方式更加灵活。
  • 可以设计出多个不同的具体装饰类,创造出多个不同行为的组合。

缺点:

  • 装饰模式增加了许多子类,如果过度使用会使程序变得很复杂。

3. 装饰器模式的主要角色

  • 抽象组件(Component)角色:定义一个抽象接口以规范准备接收附加责任的对象。
  • 具体组件(Concrete    Component)角色:实现抽象构件,通过装饰角色为其添加一些职责。
  • 抽象装饰(Decorator)角色:继承抽象构件,并包含具体构件的实例,可以通过其子类扩展具体构件的功能。
  • 具体装饰(ConcreteDecorator)角色:实现抽象装饰的相关方法,并给具体构件对象添加附加的责任。

从类图上看,装饰器模式与代理模式很像,是它们的目的不同,所以使用方法和适用场景上也就不同 ,装饰器模式与代理模式的区别:

  • 代理模式专注于对被代理对象的访问。
  • 装饰器模式专注于对被装饰对象附加额外功能。

4.装饰器的结构图

 5.装饰器的实现,以coffee为例

  •  创建抽象组件类
package com.lw.designpattern.decorate;

/**
 * @Classname Coffee
 * @Description 抽象组件类,咖啡
 * @Author lw
 * @Date 2020-01-13 09:01
 */
public interface Coffee {

    /**
     * 价格
     *
     * @return double
     */
    double price();

    /**
     * 配料
     *
     * @return String
     */
    String ingredients();
}
  • 创建具体组件类
package com.lw.designpattern.decorate;

/**
 * @Classname SimpleCoffee
 * @Description 具体组件类,原味coffee
 * @Author lw
 * @Date 2020-01-13 09:02
 */
public class SimpleCoffee implements Coffee {

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

    @Override
    public String ingredients() {
        return "coffee";
    }
}
  • 创建抽象装饰类
package com.lw.designpattern.decorate;

/**
 * @Classname AbstractCoffeeDecorator
 * @Description 抽象装饰类,咖啡的"装饰器"
 * @Author lw
 * @Date 2020-01-13 09:04
 */
public abstract class AbstractCoffeeDecorator implements Coffee {

    protected Coffee coffee;

    public AbstractCoffeeDecorator(Coffee coffee) {
        this.coffee = coffee;
    }

    /**
     * 价格
     *
     * @return double
     */
    @Override
    public double price() {
        return coffee.price();
    }

    /**
     * 配料
     *
     * @return String
     */
    @Override
    public String ingredients() {
        return coffee.ingredients();
    }
}
  • 创建具体装饰类,牛奶
package com.lw.designpattern.decorate;

/**
 * @Classname WithMilk
 * @Description 具体装饰类,牛奶
 * @Author lw
 * @Date 2020-01-13 09:10
 */
public class WithMilk extends AbstractCoffeeDecorator {

    public WithMilk(Coffee house) {
        super(house);
    }

    /**
     * 价格
     *
     * @return double
     */
    @Override
    public double price() {
        double addPrice = 1;
        return super.price() + addPrice;
    }

    /**
     * 配料
     *
     * @return String
     */
    @Override
    public String ingredients() {
        String addIngredients = "milk";
        return super.ingredients() + "," + addIngredients;
    }
}
  • 再创建一个具体装饰类,糖
package com.lw.designpattern.decorate;

/**
 * @Classname WithSugar
 * @Description 具体装饰类,糖
 * @Author lw
 * @Date 2020-01-13 09:10
 */
public class WithSugar extends AbstractCoffeeDecorator {

    public WithSugar(Coffee house) {
        super(house);
    }

    /**
     * 价格
     *
     * @return double
     */
    @Override
    public double price() {
        double addPrice = 0.5;
        return super.price() + addPrice;
    }

    /**
     * 配料
     *
     * @return String
     */
    @Override
    public String ingredients() {
        String addIngredients = "sugar";
        return super.ingredients() + ","  + addIngredients;
    }
}
  • 单元测试
  /**
     * 装饰者模式
     */
    @Test
    public void testDecorate() {
        // 原味咖啡
        Coffee c = new SimpleCoffee();
        System.out.println("花费了: " + c.price());
        System.out.println("配料: " + c.ingredients());
        System.out.println("============");

        // 增加牛奶的咖啡
        c = new WithMilk(c);
        System.out.println("花费了: " + c.price());
        System.out.println("配料: " + c.ingredients());
        System.out.println("============");

        // 增加糖的咖啡
        c = new WithSugar(c);
        System.out.println("花费了: " + c.price());
        System.out.println("配料: " + c.ingredients());
        System.out.println("============");
    }

打印结果

 6.装饰器的适用场景

  • 运行时,你需要动态地为对象增加额外职责时。
  • 当你需要一个能够代替子类的类,借助它提供额外方法时。

7.装饰器的扩展

  • Java提供的工具包中,IO相关工具就普遍大量使用了装饰器模式,例如充当装饰功能的IO类如BufferedInputStream等,又被称为高级流,通常将基本流作为高级流构造器的参数传入,将其作为高级流的一个关联对象,从而对其功能进行扩展和装饰。
  • 用BufferedInputStream和用FileInputStream去read一个文件实际使用方式上是一样的,能用FileInputStream.read(),就能用BufferedInputStream.read(),只不过,BufferedInputStream把FileInputStream包装了一下,增加了一个缓存,并不控制底层FileInputStream的read()行为。
原文地址:https://www.cnblogs.com/lwcode6/p/12185620.html