装饰器模式被大量地使用在各种框架的源码里面,真正学会了对看源码和设计软件受益匪浅。
1、装饰者和被装饰者继承同一个接口
2、装饰者给被装饰者动态修改行为
首先我们一生活中的例子来看一看装饰器模式:
/**
* @see io.netty.buffer.WrappedByteBuf;
* @see io.netty.buffer.UnreleasableByteBuf
* @see io.netty.buffer.SimpleLeakAwareByteBuf
*/
public class Decorate {
// 优惠方案
public interface OnSalePlan {
float getPrice(float oldPrice);
}
// 无优惠
public static class NonePlan implements OnSalePlan {
static final OnSalePlan INSTANCE = new NonePlan();
private NonePlan() {
}
public float getPrice(float oldPrice) {
return oldPrice;
}
}
// 立减优惠
public static class KnockPlan implements OnSalePlan {
// 立减金额
private float amount;
public KnockPlan(float amount) {
this.amount = amount;
}
public float getPrice(float oldPrice) {
return oldPrice - amount;
}
}
// 打折优惠
public static class DiscountPlan implements OnSalePlan {
// 折扣
public int discount;
private OnSalePlan previousPlan;
public DiscountPlan(int discount, OnSalePlan previousPlan) {
this.discount = discount;
this.previousPlan = previousPlan;
}
public DiscountPlan(int discount) {
this(discount, NonePlan.INSTANCE);
}
public float getPrice(float oldPrice) {
return previousPlan.getPrice(oldPrice) * discount / 10;
}
}
public static void main(String[] args) {
DiscountPlan simpleDiscountPlan = new DiscountPlan(5);
System.out.println(simpleDiscountPlan.getPrice(100));
KnockPlan previousPlan = new KnockPlan(50);
DiscountPlan complexDiscountPlan = new DiscountPlan(5, previousPlan);
System.out.println(complexDiscountPlan.getPrice(100));
}
}
我们以OnSalePlan 作为接口,装饰者或者被装饰者都继承或者实现这个接口。
NonePlan是一种实现方案、KnockPlan也是一种实现方案、DiscountPlan也是一种实现方案,但是它可以实现我们的装饰器模式。
在main函数里面,我们首先实现了一个简单的打折方案,这里没有用到装饰器模式,打印出50;重点在第二个方案,首先实例出一个立减方案,立减方案KnockPlan作为被装饰者传入到DiscountPlan打折方案里面,DiscountPlan就是装饰者,它装饰了KnockPlan的行为,使得它的行为得以改变。
在netty里面,我们以WrappedByteBuf、UnreleasableByteBuf 、SimpleLeakAwareByteBuf这三个类讲解分析里面用到的设计模式。
WrappedByteBuf是所有装饰器的基类,它继承自ByteBuf
class WrappedByteBuf extends ByteBuf {
protected final ByteBuf buf;
protected WrappedByteBuf(ByteBuf buf) {
if (buf == null) {
throw new NullPointerException("buf");
}
this.buf = buf;
}
@Override
public final boolean hasMemoryAddress() {
return buf.hasMemoryAddress();
}
@Override
public final long memoryAddress() {
return buf.memoryAddress();
}
...
}
首先看构造函数,传入一个ByteBuf实例,这个传入的实例就是被装饰者,它的行为可以被当前这个类,也就是WrappedByteBuf(也就是装饰者)动态改变。因为这个WrappedByteBuf它只是装饰器的基类,所以他只对传入的被装饰者的行为做简单的返回,没做任何修改,...后面是更多的方法,都是直接调用被装饰者的方法。
接下来看WrappedBuf的一个子类UnreleasableByteBuf,这个类一看就是什么什么不释放的类,具体什么我们先不管,我们找到源代码:
final class UnreleasableByteBuf extends WrappedByteBuf {
private SwappedByteBuf swappedBuf;
UnreleasableByteBuf(ByteBuf buf) {
super(buf);
}
...
@Override
public boolean release() {
return false;
}
...
}
首先调用父类WrappedByteBuf的构造方法,前面我们分析过,就是把被装饰者传进来,以供以后使用。然后看里面有一行 public boolean release() { return false;},我们不管它release释放了什么,反正它release就是返回false,装饰或者说是改变了被装饰者buf的行为。
另外一个WrappedByteBuf的子类SimpleLeakAwareByteBuf,这个类顾名思义就是内存泄漏自动感知的一个ByteBuf,源码:
final class SimpleLeakAwareByteBuf extends WrappedByteBuf {
private final ResourceLeak leak;
SimpleLeakAwareByteBuf(ByteBuf buf, ResourceLeak leak) {
super(buf);
this.leak = leak;
}
...
@Override
public boolean release() {
boolean deallocated = super.release();
if (deallocated) {
leak.close();
}
return deallocated;
}
...
}
构造器还是调用父类的方法,在release 这个方法里面,如果发现内存泄漏了,就执行leak.close()这个方法,然后在返回,其实也是修饰了被装饰者,动态改变了被装饰着的行为。
当然WrappedByteBuf还有很多子类的,我们目前只分析这两个来实现分析netty装饰器模式。