书接上回,本篇讲一下结构型模式-装饰器设计模式
装饰器设计模式
定义:在不改变原有对象的基础上,将动态的将功能附加到对象上。
延伸:区别于继承,它是通过装饰对象对原有对象做功能增强,属于动态组合。
UML图
Component:组件,是一个接口,定义要被装饰的方法/逻辑
ConcreteComponent:具体组件,是一个类,实现Component接口,原始类,即将要被装饰的类
Decorator:装饰器,一个抽象父类,实现了Component接口,持有一个Component属性,即被装饰对象-ConcreteComponent
ConcreteDecoratorA/B:装饰器子类,继承Decorator,实现/拓展装饰器各种装饰功能,这些功能最终都会叠加到被装饰对象-ConcreteComponent中
上面理论,刚接触者可能有理解,又有点模糊,不急上代码。
案例分析
需求:设计大宝剑攻击属性升级
基础:大宝剑,攻击属性:100
一次锻造:金晶石,攻击+10
二次锻造:木晶石,攻击+10
三次锻造:水晶石,攻击+10
四次锻造:火晶石,攻击+10
五次锻造:土晶石,攻击+10
剑类
//剑-扮演角色-Component
//定义2个方法:武器描述,攻击总值
public interface ISword {
//武器描述
String desc();
//攻击总值
int attackValue();
}
大宝剑
//大宝剑
public class BigSword implements ISword{
@Override
public String desc() {
return "大宝剑";
}
@Override
public int attackValue() {
//基本属性100
return 100;
}
}
晶石装饰器
//晶石装饰器-对应Decorator
public class CrystalDecorator implements ISword{
private ISword sword; //被装饰对象
public CrystalDecorator(ISword sword) {
this.sword = sword;
}
@Override
public String desc() {
return sword.desc() + "\n";
}
@Override
public int attackValue() {
return sword.attackValue();
}
}
金晶石
//金晶石装饰器
public class GoldCrystalDecorator extends CrystalDecorator{
public GoldCrystalDecorator(ISword sword) {
super(sword);
}
@Override
public String desc() {
return super.desc() + " 融入金晶石,攻击+10";
}
@Override
public int attackValue() {
return super.attackValue() + 10;
}
}
木晶石
//木晶石装饰器
public class WoodCrystalDecorator extends CrystalDecorator{
public WoodCrystalDecorator(ISword sword) {
super(sword);
}
@Override
public String desc() {
return super.desc() + " 融入木晶石,攻击+10";
}
@Override
public int attackValue() {
return super.attackValue() + 10;
}
}
水晶石
//水晶石装饰器
public class WaterCrystalDecorator extends CrystalDecorator{
public WaterCrystalDecorator(ISword sword) {
super(sword);
}
@Override
public String desc() {
return super.desc() + " 融入水晶石,攻击+10";
}
@Override
public int attackValue() {
return super.attackValue() + 10;
}
}
火晶石
//火晶石装饰器-对应ConcreteDecorator
public class FireCrystalDecorator extends CrystalDecorator{
public FireCrystalDecorator(ISword sword) {
super(sword);
}
@Override
public String desc() {
return super.desc() + " 融入火晶石,攻击+10";
}
@Override
public int attackValue() {
return super.attackValue() + 10;
}
}
土晶石
//土晶石装饰器
public class SoilCrystalDecorator extends CrystalDecorator{
public SoilCrystalDecorator(ISword sword) {
super(sword);
}
@Override
public String desc() {
return super.desc() + " 融入土晶石,攻击+10";
}
@Override
public int attackValue() {
return super.attackValue() + 10;
}
}
测试
public class App {
public static void main(String[] args) {
//大宝剑
ISword sword = new BigSword();
System.out.println("名称:" + sword.desc());
System.out.println("攻击值:" + sword.attackValue());
System.out.println("---------开始装饰---------");
sword = new GoldCrystalDecorator(sword); //金
sword = new WoodCrystalDecorator(sword); //木
sword = new WaterCrystalDecorator(sword); //水
sword = new SoilCrystalDecorator(sword); //火
sword = new FireCrystalDecorator(sword); //土
System.out.println("名称:" + sword.desc());
System.out.println("攻击值:" + sword.attackValue());
}
}
UML
解析
BigSword:就是被装饰的对象,已经有基本操作:desc/attackValue
GoldCrystalDecorator等:金木水火土装饰器对原先对象BigSword基本操作进行功能附加。
调用时直接使用BigSword desc/attackValue方法即可实现基本 + 附加功能
适用场景
1>扩展一个类的功能或者给一个类添加附加功能,可用
2>动态给一个对象添加功能,同时要求功能可以动态撤销,可用
优缺点
优点
继承功能补充,比继承更灵活,不改变原有对象的情况下给对象一个扩展功能,实现动态扩展
通过使用不同的装饰类以及这些装饰类的排列组合,可以实现不同效果
符合开闭原则
缺点
类结构有点多,会增加程序复杂性
当动态装饰时,多层装饰时会更复杂
VS继承
装饰器模式实现比继承更灵活
被装饰对象(BigSword)与装饰器(GoldCrystalDecorator)分离,可以根据业务需要动态添加装饰逻辑,可加,可卸载。
如果采用继承方式被修饰对象与装饰器紧耦合,就无法动态剥离了。
VS AOP
装饰模器式跟AOP在思想设计上是一致的、
AOP:面向切面编程,是一种编程范式,功能也是在不改动源码前提上,动态增加功能。
那跟装饰器模式区别在哪?
装饰器模式需要叠加额外功能, 需要主动调用装饰器,对原对象进行装饰,属于主动
AOP实现更加灵活,更加可配置,基本上跟源码没有耦合,额外功能添加是被动添加,不需要原对象做任何操作,AOP主动织入,很多情况都是原对象不知情情况下织入的。
开发案例
装饰器模式在开发用得非常多举几个例子
JDK-BufferedInputStream
File file = new File("c:/aa.txt");
FileInputStream fin = new FileInputStream(file);
BufferedInputStream bin = new BufferedInputStream(fin );
bin.read();
public class BufferedInputStream extends FilterInputStream {
public BufferedInputStream(InputStream in) {
this(in, DEFAULT_BUFFER_SIZE);
}
public BufferedInputStream(InputStream in, int size) {
super(in);
if (size <= 0) {
throw new IllegalArgumentException("Buffer size <= 0");
}
buf = new byte[size];
}
}
public class FilterInputStream extends InputStream {
protected volatile InputStream in;
protected FilterInputStream(InputStream in) {
this.in = in;
}
}
UML
从上看
InputStream--对应---Component
FileInputStream-对应---ConcreteComponent
FilterInputStream---对应---Decorator
BufferedInputStream--对应--ConcreteDecoratorA
Mybatis-Cache
Cache
public interface Cache {
String getId();
void putObject(Object key, Object value);
Object getObject(Object key);
}
PerpetualCache
public class PerpetualCache implements Cache {
private final String id;
private Map<Object, Object> cache = new HashMap<>();
public PerpetualCache(String id) {
this.id = id;
}
@Override
public String getId() {
return id;
}
@Override
public int getSize() {
return cache.size();
}
@Override
public void putObject(Object key, Object value) {
cache.put(key, value);
}
}
LruCache
里面的delegate就是被装饰对象
public class LruCache implements Cache {
//被装饰对象
private final Cache delegate;
private Map<Object, Object> keyMap;
private Object eldestKey;
public LruCache(Cache delegate) {
this.delegate = delegate;
setSize(1024);
}
@Override
public String getId() {
return delegate.getId();
}
@Override
public int getSize() {
return delegate.getSize();
}
}
Cache---对应---Component
PerpetualCache -对应---ConcreteComponent
没有---对应---Decorator
LruCache --对应--ConcreteDecoratorA
总结
装饰器模式本质:动态组合