介绍
装饰者模式(Decorator Pattern)是一种结构型设计模式,它允许在不改变对象原有结构的情况下,动态地添加功能和责任。意如起名,就类似本来有一个房子,在不改变房子本身的情况下给房子添加一些装饰品,家具等,来赋予他们新的功能。是一种继承的替代方式。
装饰者模式的主要结构由以下四个部分构成
定义抽象组件(Component):抽象组件是一个接口或者抽象类,定义了被装饰对象和装饰对象共同实现的方法。在Java中,可以使用接口或者抽象类来实现抽象组件。
定义具体组件(ConcreteComponent):具体组件是实现抽象组件接口或抽象类的一个具体对象。具体组件是被装饰的对象。
定义装饰者抽象类(Decorator):装饰者抽象类继承了抽象组件,并持有一个抽象组件的引用。装饰者抽象类中定义了一个构造函数,用于传入被装饰对象,并且在其中调用抽象组件的方法。
定义具体装饰者类(ConcreteDecorator):具体装饰者类继承了装饰者抽象类,并在其中添加新的行为或者功能。具体装饰者类可以通过组合其他具体装饰者类,实现多个装饰者的嵌套。
直接介绍有点难以理解,接下来结合示例来解释整个结构
实例
以奶茶为例,目前我们奶茶店可以制作两种奶茶,分别为杨枝甘露和芋泥啵啵,同时他们都可以增加小料,小料有芋泥,啵啵,椰果。我们可能会在后续增加新的奶茶品种,同时也可能会增加新的小料。一杯奶茶可以增加多个小料,也可以完全不添加小料。这些都是比较实际且合理的需求。
我们以这个例子来展示装饰者模式。
抽象组件
//抽象组件,定义被装饰者和装饰者都需要实现的装饰方法
public abstract interface MilkyTea {
//添加小料,这里只有一个小料装饰类,如果还需要添加的种类,可以增加额外的装饰类,也就可以增加额外的抽象方法
public abstract String addCondiments();
}
被装饰者(具体组件)
杨枝甘露
//具体组件,被装饰类,杨枝甘露
@Data
public class Mango implements MilkyTea {
@Override
public String addCondiments() {
return "杨枝甘露";
}
}
芋泥啵啵
//具体组件,被装饰类,芋泥啵啵奶茶
@Data
public class TaroBobo implements MilkyTea {
@Override
public String addCondiments() {
return "芋泥啵啵奶茶";
}
}
装饰者组件(装饰者抽象类)
@Data
//装饰者抽象类,里面需要包含被装饰者类对象,以及需要实现装饰方法
public class Condiment implements MilkyTea {
protected MilkyTea milkyTea;
public Condiment(MilkyTea milkyTea)
{
this.milkyTea=milkyTea;
}
@Override
public String addCondiments() {
return milkyTea.addCondiments();
}
}
这里有两种写法,也可以将该部分改成接口,将对应的被装饰者类对象定义转移至具体装饰者实现类
具体装饰者类
芋泥
public class Taro extends Condiment {
public Taro(MilkyTea milkyTea)
{
super(milkyTea);
}
@Override
public String addCondiments() {
return milkyTea.addCondiments()+"加小料芋泥";
}
}
啵啵
public class Bobo extends Condiment {
public Bobo(MilkyTea milkyTea)
{
super(milkyTea);
}
@Override
public String addCondiments() {
return milkyTea.addCondiments()+"加小料啵啵";
}
}
椰果
public class Coconut extends Condiment {
public Coconut(MilkyTea milkyTea)
{
super(milkyTea);
}
@Override
public String addCondiments() {
return milkyTea.addCondiments()+"加小料椰果";
}
}
测试
@Test
public void decorator() {
Mango mango = new Mango();
System.out.println(mango.addCondiments());
Bobo bobo = new Bobo(mango);
String s = bobo.addCondiments();
System.out.println(s);
Taro taro = new Taro(bobo);
String s1 = taro.addCondiments();
System.out.println(s1);
TaroBobo taroBobo = new TaroBobo();
System.out.println(taroBobo.addCondiments());
Coconut coconut = new Coconut(taroBobo);
String s2 = coconut.addCondiments();
System.out.println(s2);
}
测试结果
杨枝甘露
杨枝甘露加小料啵啵
杨枝甘露加小料啵啵加小料芋泥
芋泥啵啵奶茶
芋泥啵啵奶茶加小料椰果
总结
通过上面例子可以看出,装饰者模式具有以下一些特点
- 可以动态的增加被装饰者的装饰品,具有良好的灵活性及可扩展性,可以增加装饰品种类也可以增加被装饰者种类。
- 符合开闭原则,允许行为可以被扩展,而不需修改现有的代码。
- 一般情况下,装饰者本身可以对用户透明,用户不必知道装饰者的具体实现,只需要知道其接口。