介绍
装饰器设计模式是结构型模式的一种,它允许向一个现有的对象添加新的功能,同时又不改变其结构。
这种模式创建了一个装饰类,用来包装原有的类,并在保持类方法签名完整性的前提下,提供了额外的功能。
一般情况下,我们为了扩展一个类,常使用继承方式实现,继承会为类引入静态特征,并且随着扩展功能的增多,子类数量会越来越多。装饰器模式比继承更为灵活,可以在不增加很多子类的情况下动态扩展和撤销类的功能。
装饰器模式优点:装饰类和被装饰类可以独立发展,不会相互耦合。
装饰器模式缺点:多层装饰比较复杂,排查问题时需要层层深入比较麻烦
举例
小摊上卖的肉夹馍
一般情况下店家会提供很多种类的肉夹馍,有最简单的基础款夹馍,也有里脊肉夹馍,鸡蛋肉夹馍,牛肉肉夹馍等等。。。
将肉夹馍抽象为java 类:
/**
* 肉夹馍抽象类,所有夹馍都需继承此类
*/
public abstract class ChineseHamburger {
//抽象方法 返回肉夹馍的类型,由子类实现
public abstract void getDescription();
}
使用继承
将里脊肉夹馍,牛肉肉夹馍等 抽象为 ChineseHamburger 的子类:
/**
* 里脊肉夹馍,继承了肉夹馍抽象类
*/
public class FilletChineseHamburger extends ChineseHamburger {
//重写 getDescription 方法,输出夹馍的类型为里脊肉
@Override
public void getDescription() {
System.out.println("这是里脊肉夹馍。。。");
}
}
使用继承方式时,店家每推出一种类型的肉夹馍,都需要创建一个 ChineseHamburger 的子类,因此子类的数量会不断增加,
而且 顾客无法个性化的选取想要的食材,只能选取菜单上已有的肉夹馍类型
结论: 使用常规的继承方式会造成类数量爆炸,且不够灵活
使用装饰器模式
实际情况下,店家只提供一种基础款肉夹馍,顾客根据自身需求添加不同种类的食材(里脊,鸡蛋,烤肠,生菜等。。),最终得到顾客想要的肉夹馍类型,每加一种食材就是对肉夹馍进行了一次包装
实现装饰器模式的组件
- Component 抽象构件:
是一个接口或者抽象类,是最原始最核心的对象,比如上面的肉夹馍抽象类 ChineseHamburger - ConcreteComponent 具体构件
Component 抽象类的基本实现类,可以单独用,也可将其进行装饰,比如上面的里脊肉夹馍 - Decorator 装饰角色
一般是一个抽象类,继承自或实现 Component,它有一个指向Component 抽象构件的变量,是装饰器最关键的构件:
/**
* 肉夹馍装饰器类
*/
public abstract class Decorator extends ChineseHamburger {
private ChineseHamburger chineseHamburger = null;
public Decorator(ChineseHamburger chineseHamburger){
this.chineseHamburger = chineseHamburger;
}
@Override
public void getDescription(){
this.chineseHamburger.getDescription();
}
}
- ConcreteDecorator 具体装饰角色
EggConcreteDecorator 和 RoastSausageConcreteDecorator 是两个具体的装饰类,它们可以把基础构件装饰成新的东西,比如把一个基础肉夹馍装饰成鸡蛋或者牛肉肉夹馍
/**
* 鸡蛋肉夹馍装饰器类
*/
public class EggConcreteDecorator extends Decorator {
public EggConcreteDecorator(ChineseHamburger chineseHamburger) {
super(chineseHamburger);
}
@Override
public void getDescription() {
super.getDescription();
this.addEgg();
}
// 定义自己的修饰逻辑,这里是给肉夹馍加鸡蛋
private void addEgg() {
System.out.println("加鸡蛋。。");
}
}
/**
* 烤肠肉夹馍装饰器类
*/
public class RoastSausageConcreteDecorator extends Decorator{
public RoastSausageConcreteDecorator(ChineseHamburger chineseHamburger) {
super(chineseHamburger);
}
@Override
public void getDescription() {
super.getDescription();
this.addRoastSausage();
}
// 定义自己的修饰逻辑,这里是给肉夹馍加烤肠
private void addRoastSausage() {
System.out.println("加烤肠。。");
}
}
测试装饰器模式
用肉夹馍的示例来做个运行测试:
/**
* 肉夹馍装饰器测试
*/
public class DecoratorTst {
public static void main(String[] args) {
//首先实例化一个基础款的里脊肉肉夹馍
ChineseHamburger chineseHamburger = new FilletChineseHamburger();
// 第一次修饰,加鸡蛋
chineseHamburger = new EggConcreteDecorator(chineseHamburger);
// 第二次修饰,加烤肠
chineseHamburger = new RoastSausageConcreteDecorator(chineseHamburger);
// 修饰后运行,几种食材加在一起
chineseHamburger.getDescription();
}
}
输出:
里脊肉夹馍。。。
加鸡蛋。。
加烤肠。。
这样就把原先的基础款里脊肉夹馍,经过两步装饰,变成了豪华版的里脊肉鸡蛋烤肠肉夹馍。
版权声明:本文为bystarf原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。