装饰器模式(Decorator Pattern)提供了一种给对象灵活地、动态地添加额外功能的思路,装饰器模式是一种结构型模式。
引
日常开发中,经常需要对一个旧的类进行扩展,但是又希望遵循开闭原则不直接修改原本的类,于是我们可以创建一个子类并继承原类,并进行新增或者重写。如果扩展的次数不多,采用这种方式就可以方便快捷的完成扩展。
但是这种继承的方式是静态的,会随着扩展次数的增多,子类越来越多的同时继承关系越来越复杂,并且不同版本之间的类严重耦合。
经验和直觉告诉我们应该可以在 原有类
和 扩展
之间增加一层东西,从而降低上述的耦合。
这层东西,就是装饰器(Decorator),它可以抽象的理解成套在被装饰类外面的一层壳子,可以在这层壳子上增加各种装饰,从而达到扩展被装饰类的效果。
装饰器模式,相较于上面继承方法,是一种动态的扩展,耦合度大大降低,装饰类和被装饰类可以各自发展。
正文
LOL 中有不同的英雄,英雄都可以看做是被装饰类;每个英雄可以买不同的装备,装备可以看作是装饰。下面依据这种概念来进行举例:
实现,英雄(被装饰类)接口:
1 2 3 4 5 6 7
| public interface Hero { Integer showAttackPower(); String showBackpack(); }
|
英雄(被装饰类)实现:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| 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 "多兰两红"; } }
|
装饰器:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| 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(); } }
|
装备(装饰类)实现:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| 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 包中的输入流就是使用了装饰器模式,来看类图:
输入流有多个子类:文件输入流、字节输入流等等。。同时还有一个装饰器(过滤输入流),同时有多个子装饰器:加校验、加缓存等等。。使用的方法:
1 2 3 4 5 6 7 8
| public static void main(String[] args) { try { InputStream inputStream = new FileInputStream("src/main/Decorator.java"); inputStream = new BufferedInputStream(inputStream); } catch (FileNotFoundException e) { e.printStackTrace(); } }
|
总
装饰器模式在实际应用中还是有一定的难度的,需要结合需求灵活选择。装饰器模式的中心思想就是提供一种继承之外的方式,进而降低耦合,实现更加清晰地职责划分。
菜鸟本菜,不吝赐教,感激不尽!
更多题解源码和学习笔记:github 、CSDN 、M1ng