装饰者模式
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.其他
- 装饰者会导致类中出现许多的小对象,如果过度使用,会让程序变得复杂。
- 装饰者可以在被装饰者的行为前面或者后面加上自己的行为。
- 可以用无数个装饰者包装一个组件。