装饰模式
一、定义
装饰模式:动态地给一个对象增加一些额外的职责,就增加对象功能来说,装饰模式比生成子类实现更为灵活。其别名也可以称为包装器,与适配器模式的别名相同,但它们适用于不同的场合。根据翻译的不同,装饰模式也有人称之为“油漆工模式”。
二、业务场景
提到装饰,我们先来想一下生活中有哪些装饰:
- 女生的首饰:戒指,耳环,项链等。
- 家居装饰品:粘钩,镜子,笔画,盆栽等。
我们为什么需要这些装饰品呢?很容易想到为了好看,这是装饰品可以增加美观。但是粘钩和镜子不一样,他们是为了方便我们挂东西和洗漱。所以我们可以总结出装饰品共有俩种功能:
- 增强原有特性:我们本身就有一定的颜值的,但是增加装饰品可以提高我们的颜值。同样的房子本身就有一定的美观度,家居装饰提高了房屋的美观度。
- 增加新的特性:在墙上的粘钩,让墙壁有了挂东西的功能。在洗漱台装上镜子,让洗漱台有了照镜子的功能。
而且我们发现装饰品不会改变物品本身,只是起到一个锦上添花的作用,装饰模式也是一样,他的主要作用:
- 增强一个原有类的功能。
- 为一个类添加新的功能。
三、装饰模式分类
1、透明装饰模式
透明装饰模式:仅用于增强功能,并不会改变原有类的功能,这种装饰模式称之为透明装饰模式。
实例代码:
/**
* 新建颜值接口
*/
public interface IBeauty {
int getBeautyValue();
}
/**
* 新建Me类
*/
public class Me implements IBeauty {
@Override
public int getBeautyValue() {
return 100;
}
}
/**
* 戒指装饰类,将 Me 包装起来
*/
public class RingDecorator implements IBeauty {
private final IBeauty me;
public RingDecorator(IBeauty me) {
this.me = me;
}
@Override
public int getBeautyValue() {
return me.getBeautyValue() + 20;
}
}
/**
* 耳环装饰类
*/
public class EarringDecorator implements IBeauty {
private final IBeauty me;
public EarringDecorator(IBeauty me) {
this.me = me;
}
@Override
public int getBeautyValue() {
return me.getBeautyValue() + 50;
}
}
/**
* 项链装饰类
*/
public class NecklaceDecorator implements IBeauty {
private final IBeauty me;
public NecklaceDecorator(IBeauty me) {
this.me = me;
}
@Override
public int getBeautyValue() {
return me.getBeautyValue() + 80;
}
}
/**
* 客户端测试:
*/
public class Client {
@Test
public void show() {
IBeauty me = new Me();
System.out.println("我原本的颜值:" + me.getBeautyValue());
// 随意挑选装饰
IBeauty meWithNecklace = new NecklaceDecorator(me);
System.out.println("戴上了项链后,我的颜值:" + meWithNecklace.getBeautyValue());
// 多次装饰
IBeauty meWithManyDecorators = new NecklaceDecorator(new RingDecorator(new EarringDecorator(me)));
System.out.println("戴上耳环、戒指、项链后,我的颜值:" + meWithManyDecorators.getBeautyValue());
// 任意搭配装饰
IBeauty meWithNecklaceAndRing = new NecklaceDecorator(new RingDecorator(me));
System.out.println("戴上戒指、项链后,我的颜值:" + meWithNecklaceAndRing.getBeautyValue());
}
}
2、半透明装饰模式
并没有去改变原有的功能,只是去扩展了新的功能,这种模式在装饰模式中称之为半透明装饰模式。
我们用程序来模拟一下房屋装饰粘钩后,新增了挂东西功能的过程:
/**
* 新建房屋接口:
*/
public interface IHouse {
void live();
}
/**
* 房屋类:
*/
public class House implements IHouse{
@Override
public void live() {
System.out.println("房屋原有的功能:居住功能");
}
}
/**
* 新建粘钩装饰器接口,继承自房屋接口:
*/
public interface IStickyHookHouse extends IHouse{
void hangThings();
}
/**
* 粘钩装饰类:
*/
public class StickyHookDecorator implements IStickyHookHouse {
private final IHouse house;
public StickyHookDecorator(IHouse house) {
this.house = house;
}
@Override
public void live() {
house.live();
}
@Override
public void hangThings() {
System.out.println("有了粘钩后,新增了挂东西功能");
}
}
/**
* 户端测试:
*/
public class Client {
@Test
public void show() {
IHouse house = new House();
house.live();
IStickyHookHouse stickyHookHouse = new StickyHookDecorator(house);
stickyHookHouse.live();
stickyHookHouse.hangThings();
}
}
那么我们能否让 IMirrorHouse 继承自 IStickyHookHouse,以实现新增两个功能呢?
可以,但那样做的话两个装饰类之间有了依赖关系,那就不是装饰模式了。装饰类不应该存在依赖关系,而应该在原本的类上进行装饰。这就意味着,半透明装饰模式中,我们无法多次装饰。
有的同学会问了,既增强了功能,又添加了新功能的装饰模式叫什么呢?
—— 举一反三,肯定是叫全不透明装饰模式!
—— 并不是!只要添加了新功能的装饰模式都称之为半透明装饰模式,他们都具有不可以多次装饰的特点。仔细理解上文半透明名称的由来就知道了,“透明”指的是我们无需知道被装饰者具体的类,既增强了功能,又添加了新功能的装饰模式仍然具有半透明特性。