装饰器模式(Decorator Pattern)提供了一种给对象灵活地、动态地添加额外功能的思路,装饰器模式是一种结构型模式。
引
日常开发中,经常需要对一个旧的类进行扩展,但是又希望遵循开闭原则不直接修改原本的类,于是我们可以创建一个子类并继承原类,并进行新增或者重写。如果扩展的次数不多,采用这种方式就可以方便快捷的完成扩展。
但是这种继承的方式是静态的,会随着扩展次数的增多,子类越来越多的同时继承关系越来越复杂,并且不同版本之间的类严重耦合。
经验和直觉告诉我们应该可以在 原有类
和 扩展
之间增加一层东西,从而降低上述的耦合。
这层东西,就是装饰器(Decorator),它可以抽象的理解成套在被装饰类外面的一层壳子,可以在这层壳子上增加各种装饰,从而达到扩展被装饰类的效果。
装饰器模式,相较于上面继承方法,是一种动态的扩展,耦合度大大降低,装饰类和被装饰类可以各自发展。
正文
LOL 中有不同的英雄,英雄都可以看做是被装饰类;每个英雄可以买不同的装备,装备可以看作是装饰。下面依据这种概念来进行举例:
实现,英雄(被装饰类)接口:
//英雄接口
public interface Hero {
//攻击力
Integer showAttackPower();
//背包中的装备
String showBackpack();
}
英雄(被装饰类)实现:
//实现两个英雄:提莫和辛德拉
public class Timo implements Hero {
@Override
public Integer showAttackPower() {
return 55;
}
@Override
public String showBackpack() {
return "腐败药水";
}
}
public class Sindra implements Hero {
@Override
public Integer showAttackPower() {
return 53;
}
@Override
public String showBackpack() {
return "多兰两红";
}
}
装饰器:
//装饰器
public abstract class Decorator implements Hero {
private Hero hero;
//通过构造方法传入被装饰类
public Decorator(Hero hero) {
this.hero = hero;
}
@Override
public Integer showAttackPower() {
return hero.showAttackPower();
}
@Override
public String showBackpack() {
return hero.showBackpack();
}
}
装备(装饰类)实现:
//实现两个装备:帽子和面具
public class Hat extends Decorator {
public Hat(Hero hero) {
super(hero);
}
@Override
public Integer showAttackPower() {
return super.showAttackPower() + 80;
}
@Override
public String showBackpack() {
return super.showBackpack() + "、大帽子";
}
}
public class Mask extends Decorator {
public Mask(Hero hero) {
super(hero);
}
@Override
public Integer showAttackPower() {
return super.showAttackPower() + 60;
}
@Override
public String showBackpack() {
return super.showBackpack() + "、大面具";
}
}
看一下 IDEA 生成的类图:
照例,依然是找一个 JDK 中装饰器模式的应用,IO 包中的输入流就是使用了装饰器模式,来看类图:
输入流有多个子类:文件输入流、字节输入流等等。。同时还有一个装饰器(过滤输入流),同时有多个子装饰器:加校验、加缓存等等。。使用的方法:
public static void main(String[] args) {
try {
InputStream inputStream = new FileInputStream("src/main/Decorator.java");
inputStream = new BufferedInputStream(inputStream);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
总
装饰器模式在实际应用中还是有一定的难度的,需要结合需求灵活选择。装饰器模式的中心思想就是提供一种继承之外的方式,进而降低耦合,实现更加清晰地职责划分。
菜鸟本菜,不吝赐教,感激不尽!