1 定义
装饰模式也成为包装模式,此设计模式属于结构型模式。
定义:动态地给一个对象添加一些额外的职责。就增加功能来说,装饰模式相比生成子类更为灵活。
模式结构
角色介绍
- Component:抽象组件
可以是一个接口或者抽象类,定义我们最核心的对象,也就是被装饰的原始对象。 - ConcreteComponent:组件的具体实现
Component类的基本实现,也就是要装饰的具体对象。 - Decorator:抽象装饰者
作用是为了装饰我们的组件对象,其内部必有一个指向Component对象的引用。 - ConcreteDecoratorA:抽象装饰者的具体实现。
- ConcreteDecoratorB:抽象装饰者的具体实现。
通用模式代码
- 抽象组件,被装饰的原始对象
public abstract class Component {
/**
* 抽象的方法,可以有多个
*/
public abstract void operate();
}
- 组件的具体实现,即被装饰的具体对象
public class ConcreteComponent extends Component{
@Override
public void operate() {
// 在这里写你的逻辑
}
}
- 抽象装饰者,其内部一定要有一个指向组件对象的引用。
public class Decorator extends Component{
private Component mComponent; // 持有一个Component对象的引用
/**
* 构造方法
* @param component
*/
public Decorator(Component component){
this.mComponent=component;
}
@Override
public void operate() {
mComponent.operate();
}
}
- 抽象装饰者的具体实现
public class ConcreteDecoratorA extends Decorator{
/**
* 构造方法
*
* @param component
*/
public ConcreteDecoratorA(Component component) {
super(component);
}
@Override
public void operate() {
// 装饰方法A和B的调用顺序可变
operateA();
super.operate();
operateB();
}
/**
* 自定义的装饰方法
*/
public void operateA(){
// 装饰逻辑
}
/**
* 自定义的装饰方法
*/
public void operateB(){
// 装饰逻辑
}
}
public class ConcreteDecoratorB extends Decorator{
/**
* 构造方法
*
* @param component
*/
public ConcreteDecoratorB(Component component) {
super(component);
}
@Override
public void operate() {
// 装饰方法A和B的调用顺序可变
operateA();
super.operate();
operateB();
}
/**
* 自定义的装饰方法
*/
public void operateA(){
// 装饰逻辑
}
/**
* 自定义的装饰方法
*/
public void operateB(){
// 装饰逻辑
}
}
- 测试代码
// 构造被装饰的对象
Component component=new ConcreteComponent();
// 根据组件对象构造装饰者对象A并调用,此时相当于给组件对象添加装饰者A的功能方法
Decorator decoratorA=new ConcreteDecoratorA(component);
decoratorA.operate();
// 根据组件对象构造装饰者对象B并调用,此时相当于给组件对象添加装饰者B的功能方法
Decorator decoratorB=new ConcreteDecoratorB(component);
decoratorB.operate();
三 实例
我们再以制作奶茶为例,在桥接模式里,我们实现了奶茶两个维度的变化,大小杯和加不加糖。在装饰模式下,我们要实现装饰一杯奶茶,动态地给奶茶添加一些功能。比如加冰,加蓝莓,加珍珠,计算价格等。
- 抽象组件,被装饰的原始对象,在我们的实例是指制作一杯饮料
/*
* 抽象组件,被装饰的原始对象
* @author Jackson
* @version 1.0.0
* since 2019 03 13
*/
public abstract class Beverage {
/**
* 抽象方法,制作饮料
*/
public abstract void makeBeverage();
}
- 组件的具体实现,被装饰的具体对象,在我们的实例,制作一杯奶茶
/*
* 组件的具体实现,被装饰的具体对象
* @author Jackson
* @version 1.0.0
* since 2019 03 13
*/
public class MilkTea extends Beverage {
@Override
public void makeBeverage() {
// 奶茶的基本逻辑
System.out.println(" 添加奶茶 ");
}
}
- 抽象的装饰者,其内部保持一个被装饰类的引用
/*
* 抽象的装饰者
* @author Jackson
* @version 1.0.0
* since 2019 03 13
*/
public abstract class Decorator extends Beverage {
protected Beverage mBeverage; // 其内部保持一个被装饰类的引用
/**
* 构造方法
* @param beverage
*/
public Decorator(Beverage beverage){
this.mBeverage=beverage;
}
@Override
public void makeBeverage() {
// 调用Beverage的makeBeverage()方法)
mBeverage.makeBeverage();
}
}
- 具体装饰者,加蓝莓,加冰,加蓝莓的奶茶
/*
* 具体装饰者,加蓝莓
* @author Jackson
* @version 1.0.0
* since 2019 03 13
*/
public class BlueberryDecorator extends Decorator{
/**
* 构造方法
*
* @param beverage
*/
public BlueberryDecorator(Beverage beverage) {
super(beverage);
}
@Override
public void makeBeverage() {
// 顺序:加冰--加饮料--加蓝莓--收钱,顺序按照需求可变
addIce();
super.makeBeverage();
addBlueberry();
price();
}
/**
* 添加冰块
*/
private void addIce(){
System.out.println(" 添加冰块 ");
}
/**
* 添加蓝莓
*/
private void addBlueberry(){
System.out.println(" 添加蓝莓 ");
}
/**
* 计算价格
*/
private void price(){
System.out.println(" 蓝莓奶茶的价格是5元 ");
}
}
- 具体装饰者,加珍珠的奶茶
/*
* 具体装饰者,珍珠奶茶
* @author Jackson
* @version 1.0.0
* since 2019 03 13
*/
public class PearlDecorator extends Decorator{
/**
* 构造方法
*
* @param beverage
*/
public PearlDecorator(Beverage beverage) {
super(beverage);
}
@Override
public void makeBeverage() {
// 顺序:收钱--加珍珠丸子--加饮料,顺序按照需求可变
price();
addPearl();
super.makeBeverage();
}
/**
* 添加珍珠丸子
*/
private void addPearl(){
System.out.println(" 添加珍珠丸子 ");
}
/**
* 计算价格
*/
private void price(){
System.out.println(" 珍珠奶茶的价格是6元 ");
}
}
- 测试代码
// 首先要现有一杯奶茶
MilkTea milkTea=new MilkTea();
System.out.println("------制作蓝莓奶茶-------");
// 制作蓝莓奶茶
BlueberryDecorator blueberryDecorator=new BlueberryDecorator(milkTea);
blueberryDecorator.makeBeverage();
// 制作珍珠奶茶
System.out.println("------制作珍珠奶茶-------");
PearlDecorator pearlDecorator=new PearlDecorator(milkTea);
pearlDecorator.makeBeverage();
运行结果
四 优点
- 比继承更灵活
装饰模式比继承更加灵活,继承是静态的,而且一旦继承,所有子类都有一样的功能,而装饰模式把功能分离到每个装饰器中,然后通过组合的方式,组合的方式决定装饰后对象的最终功能。 - 更容易复用功能
装饰模式把一系列复杂的功能分散到每个装饰器中,一般一个装饰器只实现一个功能,从而可以更好地复用装饰器。
五 使用场景
- 需要扩展一个类的功能,或者给一个类增加附加功能时可以考虑使用装饰者模式。