装饰器模式(Decorator Pattern),在不改变原有的一个类的情况下,动态的扩展一个对象的功能。
装饰器通过持有一个对象,将其包裹起来,并增强这个对象的功能。
看上面的说明并不好理解,我们举个例子。
比如平时我们吃的馒头,有各式各样的,比如普通的白馒头,还有加了糖的甜馒头,还有捏了各种造型的馒头,比如外形是小兔子馒头,小燕子馒头等。
按照常规的实现,我们可能是先写一个馒头制作步骤的接口,各种不同馒头类去实现接口中的馒头制作方法,new哪种馒头,就制作哪种馒头。
用装饰器模式后,我们做甜味馒头,其步骤和方法也是基于普通馒头的做法,稍加更改,就能完成甜味馒头的制作。所以我们制作甜味馒头,就让甜味馒头的制作类中持有一个普通馒头的对象,在需要更改步骤的方法中做修改,这样就相当于增强了原来普通馒头中某些步骤额功能,从而制作出新品种的馒头。
来看代码演示。
1、定义馒头制作接口
package com.itzhimei.study.design.decorator;
/**
* @Auther: www.itzhimei.com
* @Description:
*/
public interface ISteamedBun {
/**
* 准备材料
*/
void prepare();
/**
* 和面
*/
void kneadDough();
/**
* 蒸馒头
*/
void steamed();
/**
* 做馒头
*/
void make();
}
2、制作普通馒头
package com.itzhimei.study.design.decorator;
/**
* @Auther: www.itzhimei.com
* @Description:
*/
public class NormalSteamedBun implements ISteamedBun {
@Override
public void prepare() {
System.out.println("准备食材:发面...");
}
@Override
public void kneadDough() {
System.out.println("和面...");
}
@Override
public void steamed() {
System.out.println("蒸馒头,出锅...");
}
@Override
public void make() {
this.prepare();
this.kneadDough();
this.steamed();
}
}
2、制作甜味馒头,我们在和面的时候,加了糖,最后的馒头就是甜味的了
package com.itzhimei.study.design.decorator;
/**
* @Auther: www.itzhimei.com
* @Description:
*/
public class SweetSteamedBun extends NormalSteamedBun {
NormalSteamedBun steamedBun;
public SweetSteamedBun(NormalSteamedBun steamedBun) {
this.steamedBun = steamedBun;
}
/**
* 加糖的步骤当然也可以放到发酵的阶段,个人觉得放在和面接阶段
*/
@Override
public void kneadDough() {
System.out.println("面粉中加糖,调甜味...");
steamedBun.kneadDough();
}
}
3、制作小鸟造型馒头,这里也是一样,和完面,把馒头做出小鸟造型
package com.itzhimei.study.design.decorator;
/**
* @Auther: www.itzhimei.com
* @Description:
*/
public class BirdSteamedBun extends NormalSteamedBun {
NormalSteamedBun steamedBun;
public BirdSteamedBun(NormalSteamedBun steamedBun) {
this.steamedBun = steamedBun;
}
@Override
public void kneadDough() {
steamedBun.kneadDough();
System.out.println("和面后,开始给馒头做成小鸟造型...");
}
}
4、测试(仔细观察测试代码中制作小鸟造型甜味馒头的代码)
package com.itzhimei.study.design.decorator;
/**
* @Auther: www.itzhimei.com
* @Description:
*/
public class Client {
public static void main(String[] args) {
NormalSteamedBun normalSteamedBun = new NormalSteamedBun();
System.out.println("------【甜味】馒头制作开始------");
SweetSteamedBun sweetSteamedBun = new SweetSteamedBun(normalSteamedBun);
sweetSteamedBun.make();
System.out.println("------【甜味】馒头制作结束------");
System.out.println("------小鸟造型【普通】馒头制作开始------");
BirdSteamedBun normalBirdSteamedBun = new BirdSteamedBun(normalSteamedBun);
normalBirdSteamedBun.make();
System.out.println("------小鸟造型【普通】馒头制作结束------");
System.out.println("------小鸟造型【甜味】馒头制作开始------");
BirdSteamedBun birdSweetSteamedBun = new BirdSteamedBun(sweetSteamedBun);
birdSweetSteamedBun.make();
System.out.println("------小鸟造型【甜味】馒头制作结束------");
}
}
输出:
------【甜味】馒头制作开始------
准备食材:发面...
面粉中加糖,调甜味...
和面...
蒸馒头,出锅...
------【甜味】馒头制作结束------
------小鸟造型【普通】馒头制作开始------
准备食材:发面...
和面...
和面后,开始给馒头做成小鸟造型...
蒸馒头,出锅...
------小鸟造型【普通】馒头制作结束------
------小鸟造型【甜味】馒头制作开始------
准备食材:发面...
面粉中加糖,调甜味...
和面...
和面后,开始给馒头做成小鸟造型...
蒸馒头,出锅...
------小鸟造型【甜味】馒头制作结束------
请大家仔细看测试类中,最后制作小鸟造型甜味馒头的方法,是制作小鸟馒头的类,持有了一个制作甜味馒头的对象,基于甜味馒头,加上小鸟馒头的制作方法,就制作出了小鸟造型甜味馒头。
也就是做,我们可以认意组合各种馒头的对象,这样就能做出各种各样的馒头,这就是装饰器模式的威力。这就好像是积木一样,基于几块基本的木块,可以让你摆出各种造型。
类结构图:
![](https://www.itzhimei.com/wp-content/uploads/2020/07/image-19.png)
总结:装饰器模式意在对一个对象的功能进行增强,通过持有一个对象,来增强其功能。我们demo中,继承了普通馒头,就是为了能让各种馒头都作为对象,传入到另一种馒头制作类中,从而实现各种组合和装饰效果。