装饰者模式
1. 定义
装饰者模式动态的将责任附加到对象上。如要扩展功能,装饰者提供了比继承更有弹性的替代方案。
2. 类图
3. Example
假如有这样一个需求:有一天,奶茶店的老板喊你给他们做一个简单版的计算价格程序。新店开张,供应的饮料有奶茶(8元)、红茶(7元)、绿茶(5元)三种,提供的配料有波霸1元,布丁5元,红豆3元。
则可如下设计:
Component及其实现如下:
package com.gitlearning.hanldegit.patterns.decorator; /** * 相当于Component */ public abstract class Beverage { String description = "Unkown beverage"; public String getDescription() { return description; } public abstract double cost(); } class MilkTea extends Beverage { @Override public String getDescription() { return "奶茶"; } @Override public double cost() { return 8.00; } } class RedTea extends Beverage { @Override public String getDescription() { return "红茶"; } @Override public double cost() { return 7.00; } } class GreenTea extends Beverage { @Override public String getDescription() { return "绿茶"; } @Override public double cost() { return 5.00; } }
Decorator及其实现如下:
package com.gitlearning.hanldegit.patterns.decorator; public abstract class CondimentDecorator extends Beverage { @Override public abstract String getDescription(); } class RedBean extends CondimentDecorator { Beverage beverage; public RedBean(Beverage beverage) { this.beverage = beverage; } @Override public String getDescription() { return beverage.getDescription() + "添加红豆"; } @Override public double cost() { return beverage.cost() + 3.00; } } class Pudding extends CondimentDecorator { Beverage beverage; public Pudding(Beverage beverage) { this.beverage = beverage; } @Override public String getDescription() { return beverage.getDescription() + "添加布丁"; } @Override public double cost() { return beverage.cost() + 5.00; } } class Boba extends CondimentDecorator { Beverage beverage; public Boba(Beverage beverage) { this.beverage = beverage; } @Override public String getDescription() { return beverage.getDescription() + "添加波霸"; } @Override public double cost() { return beverage.cost() + 1.00; } }
测试代码如下:
package com.gitlearning.hanldegit.patterns.decorator; import org.junit.jupiter.api.Test; public class DecoratorTest { @Test void test() { // 来一杯加波霸和布丁的奶茶 Beverage milkTea = new MilkTea(); milkTea = new Pudding(milkTea); milkTea = new Boba(milkTea); System.err.println(milkTea.getDescription() + "¥"+ milkTea.cost()); // 来一杯加红豆的绿茶 Beverage greenTea = new GreenTea(); greenTea = new RedBean(greenTea); System.err.println(greenTea.getDescription() + "¥"+ greenTea.cost()); // 来一杯加红豆、布丁、波霸的红茶 Beverage redTea = new RedTea(); redTea = new Pudding(redTea); redTea = new Boba(redTea); redTea = new RedBean(redTea); System.err.println(redTea.getDescription() + "¥"+ redTea.cost()); } }
发现输出为:
奶茶添加布丁添加波霸¥14.0 绿茶添加红豆¥8.0 红茶添加布丁添加波霸添加红豆¥16.0
4. 使用
1. Java I/O
InputStream作为抽象Component,
Component,像BufferedInputStream装饰了FileInputStream,增加了readLine()和缓冲输入,LineNumberInputStream()则增加了计算行数的能力。
2. Mybatis
5.其他
- 装饰者会导致类中出现许多的小对象,如果过度使用,会让程序变得复杂。
- 装饰者可以在被装饰者的行为前面或者后面加上自己的行为。
- 可以用无数个装饰者包装一个组件。