装饰器模式:藏在漫威电影里的设计模式
你或许不熟悉装饰器模式,但是漫威电影系列你肯定并不陌生,在电影播出之后,或许你听过这样的声音:
一个紫色番薯,打了一个响指,众多超级英雄消失一半。
可是番薯还是那个番薯,响指还是那个响指,是什么让这两个结合在一起拥有了强大的力量?答案就是:无限手套。电影很精彩,而与之巧合的是,手套的工艺和装饰器模式风格极为相似,所以今天就借来灭霸的手套,研究研究矮人族所制造的产品究竟有多么神奇。
装饰器模式的定义:
允许向一个现有的对象添加新的功能,同时又不改变其结构
🌰:手套每镶嵌一个宝石就增加一个超能力,而之前原本的能力更并不受影响,仍然可以使用。这就是手套无敌的秘密,也就是装饰器模式的魅力所在,让我们看一下用代码是如何实现的。
代码实现
装饰器模式,需要让所有使用的类都来自同一个接口,只有“同一类型”才能互相装饰
所以定义一个 Equipment 接口表示我们所有的装备,action 方法表示每个装备具有的功能
public interface Equipment {
void action();
}
我们定义两种场景: 徒手戴宝石、手套镶嵌宝石
- 徒手属于(天生自带)装备的一种,所以我们实现 Equipment 接口实现 action 方法
public class Hand implements Equipment {
@Override
public void action() {
System.out.println("手可以戴");
}
}
- 手套也是同理
public class Glove implements Equipment {
@Override
public void action() {
System.out.println("手套可以镶嵌");
}
}
- 接下来我们定义装饰类也就是 Diamond 宝石抽象类,因为宝石也是装备的一种,所以也需要实现 Equipment。 而我们的装饰有很多种宝石,所以定义装饰类用来实现多态从而装饰对象(手套、手)。
public abstract class Diamond implements Equipment{
Equipment equipment;
public Diamond(Equipment equipment) {
this.equipment = equipment;
}
@Override
public void action() {
equipment.action();
}
}
构造器传入被装饰对象,这就是我们开头所提到的,所有使用的类都需要“同一类型”,这样才能将无论是原始对象,还是被装饰过的对象都能以 Equipment 类型传进去,从而再次装饰。
- 创建三个宝石,实现 Diamond 抽象类,从而具体化每个宝石的功能
public class RedDiamond extends Diamond {
public RedDiamond(Equipment equipment) {
super(equipment);
}
@Override
public void action() {
super.action();
System.out.println("红色现实宝石");
}
}
注意在宝石子类里面,每个 action 方法都额外执行了 super.action 方法,每个被装饰对象的 action 方法都会被执行。结合起来,整体功能是这样的👇
给手套镶嵌绿宝石,在这基础上再镶嵌红宝石。每次执行宝石本身功能之前都会先去执行super.action 直到执行了手套的功能后再返回执行宝石各自的功能,最终执行完所有功能。
- 以此类推,额外两个宝石类
public class GreenDiamond extends Diamond {
public GreenDiamond(Equipment equipment) {
super(equipment);
}
@Override
public void action() {
super.action();
System.out.println("绿色时间宝石");
}
}
public class BlueDiamond extends Diamond {
public BlueDiamond(Equipment equipment) {
super(equipment);
}
@Override
public void action() {
super.action();
System.out.println("蓝色空间宝石");
}
}
- 测试代码:
public class decoratorTest {
public static void main(String[] args) {
System.out.println("---------徒手----------");
Equipment hand = new Hand();
hand.action();
System.out.println();
Diamond redDiamond = new RedDiamond(hand);//用红宝石装饰手
redDiamond.action();
System.out.println();
Diamond greenAndRedDiamond = new GreenDiamond(redDiamond);//继续用绿宝石装饰
greenAndRedDiamond.action();
System.out.println("---------戴手套----------");
Equipment glove = new Glove();
glove.action();
System.out.println();
Diamond greenDiamond = new GreenDiamond(glove);//绿宝石装饰手套
greenDiamond.action();
System.out.println();
Diamond blueDiamond = new BlueDiamond(glove);//卸下绿宝石,镶嵌蓝宝石
blueDiamond.action();
}
}
- 运行结果:
可以看出,每个装饰类可以装饰原本对象,也可以装饰被装饰过的对象,各个装饰类之间相互独立,实现各自功能。
我是 Haoo,一个乐观的码农,撰写有趣的文章。 如果这篇文章帮助到你,请收藏⭐点赞👍加关注👀,跟踪不迷路(🌻◡‿◡)
转载自:https://juejin.cn/post/7148972431834054670