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()行为。