版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/www1575066083/article/details/80937685
1、基本介绍:
- 装饰模式又名包装(Wrapper)模式。装饰模式以对客户端透明的方式扩展对象的功能,是继承关系的一个替代方案。
- 动态地给一个对象增删一些额外的功能。(继承不能做到这一点,继承的功能是静态的,不能动态增删。
2、成员:
抽象构件(Component)角色:
它是具体构件和抽象装饰类的共同父类,声明了在具体构件中需要实现的业务方法,它的引入可以使客户端以一致的方式处理未被装饰的对象以及装饰之后的对象,实现客户端的透明操作。
具体构件(ConcreteComponent)角色【被装饰对象】:
它是抽象构件类的子类,用于定义具体的构件对象,实现了在抽象构件中声明的方法,装饰器可以给它增加额外的职责(方法)。
抽象装饰(Decorator)角色:【设计核心所在】
- 它也是抽象构件类的子类,用于给具体构件增加职责,但是具体职责在其子类中实现。
- 它维护一个指向抽象构件对象的引用,通过该引用可以调用装饰之前构件对象的方法,并通过其子类扩展该方法,以达到装饰的目的。
具体装饰(ConcreteDecorator)角色:【继承抽象装饰类】
- 它是抽象装饰类的子类,负责向构件添加新的职责。
- 每一个具体装饰类都定义了一些新的行为,它可以调用在抽象装饰类中定义的方法,并可以增加新的方法用以扩充对象的行为。
3、场景:
- 动态地给一个对象增删一些额外的功能。
- 当不能采用继承的方式对系统进行扩展或者采用继承不利于系统扩展和维护时可以使用装饰模式。不能采用继承的情况主要有两类:第一类是系统中存在大量独立的扩展,为支持每一种扩展或者扩展之间的组合将产生大量的子类,使得子类数目呈爆炸性增长;第二类是因为类已定义为不能被继承(如 Java 语言中的 final 类)。
4、透明装饰模式与半透明装饰模式:
4.1、透明装饰模式:【具体装饰对象的引用变量为抽象构建类型】
- 在透明装饰模式中,要求客户端完全针对抽象编程,装饰模式的透明性要求客户端程序不应该将对象声明为具体构件类型或具体装饰类型,而应该全部声明为抽象构件类型。对于客户端而言,具体构件对象和具体装饰对象没有任何区别。
- 透明装饰模式可以让客户端透明地使用装饰之前的对象和装饰之后的对象,无须关心它们的区别,此外,还可以对一个已装饰过的对象进行多次装饰,得到更为复杂、功能更为强大的对象。
4.2、半透明装饰模式:【具体装饰对象的引用变量为非抽象构建类型】
- 有时我们需要单独调用新增的业务方法。为了能够调用到新增方法,我们不得不用具体装饰类型来定义装饰之后的对象,而具体构件类型还是可以使用抽象构件类型来定义,这种装饰模式即为半透明装饰模式,也就是说,对于客户端而言,具体构件类型无须关心,是透明的;但是具体装饰类型必须指定,这是不透明的。
- 其最大的缺点在于不能实现对同一个对象的多次装饰,而且客户端需要有区别地对待装饰之前的对象和装饰之后的对象。
5、实现:【透明装饰模式】
//抽象构建角色接口
public interface DrinkI {
//获取饮料的描述信息
String getDescription();
//获取饮料的价格
double getPrice();
}
//具体构建角色对象
public class CoffeeA implements DrinkI {
private String description = "A品种咖啡";
@Override
public String getDescription() {
return description;
}
@Override
public double getPrice() {
return 10;
}
}
//装饰类
public class DrinkWrapper implements DrinkI{
protected DrinkI drinkI; //维持一个对抽象构件对象的引用
public DrinkWrapper(DrinkI drinkI) {
this.drinkI = drinkI;
}
@Override
public String getDescription() {
return drinkI.getDescription();
}
@Override
public double getPrice() {
return drinkI.getPrice();
}
}
//向饮料中添加牛奶,价格增加50
public class DrinkWrapperMilk extends DrinkWrapper{
public DrinkWrapperMilk(DrinkI drinkI) {
super(drinkI);
}
@Override
public String getDescription() {
return drinkI.getDescription()+"添加一份牛奶";
}
@Override
public double getPrice() {
return drinkI.getPrice()+50;
}
}
//向饮料中添加蜂蜜,价格增加20
public class DrinkWrapperHoney extends DrinkWrapper{
public DrinkWrapperHoney(DrinkI drinkI) {
super(drinkI);
}
@Override
public String getDescription() {
return drinkI.getDescription()+"添加一份蜂蜜";
}
@Override
public double getPrice() {
return drinkI.getPrice()+20;
}
}
//测试类
public class Test {
public static void main(String[] args) {
DrinkI coffeeA, drinkMilk, drinkHoney;
coffeeA = new CoffeeA();
drinkMilk = new DrinkWrapperMilk(coffeeA);
System.out.println("饮料品种:" + drinkMilk.getDescription() + "\n总价格:" + drinkMilk.getPrice());
drinkHoney = new DrinkWrapperHoney(drinkMilk);
System.out.println("饮料品种:" + drinkHoney.getDescription() + "\n总价格:" + drinkHoney.getPrice());
}
}
输出:
饮料品种:A品种咖啡添加一份牛奶
总价格:60.0
饮料品种:A品种咖啡添加一份牛奶添加一份蜂蜜
总价格:80.0