装饰者的应用#
所谓装饰者,说白了,目的就是对现有的对象进行增强,装饰者设计模式最大的优点就是,它在扩展类原有功能的基础上还避免的类爆炸的情况
Netty中的装饰者模式的应用#
ByteBuf
是netty中重要的数据容器类,我们看它是如何设计的,如下图
我们可以看到,ByteBuf
的直接实现类有五个,忽略WrappedByteBuf
这个类,其实直接实现类有四个,为什么要忽略掉WrappedByteBuf
呢? 因为是它是ByteBuf
装饰者的基类; 它本身没有任何实现任何功能;
netty的设计者在设计ByteBuf
的继承体系时,发现上图中的四个直接实现类可能都需要添加新的功能,这俩功能是
- 不可释放的功能
- 简单的泄漏感知的功能
怎么扩展这个功能呢?
如果选择继承的话,现有的四个类全部多出两个子类,让子类添加上特定的功能, 虽然解决了问题,但是类的数量出现了爆炸式的增长 从原来的4长到了 4+4*2
看上面的图,其实netty的设计者选择的处理模式是装饰者模式,只添加了三个类,就达到了同样的效果
装饰者的设计套路#
- 添加一个装饰者顶级类,这个类和需要装饰的组件类在继承处于相等的地位
- 这个装饰者类并不作任何的构工作,维护着
ByteBuf
的引用, 重写的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
的类型的参数,并把它传递给它的父类,用户在装饰者时,会把创建的最上面的四种待装饰的组件类以构造方法的形式传递进去,整个体系就运行起来了, 而且装饰者可以按照自己的需求重写父类的方法, 或者在现在的基础上添加新的方法调用进行增强
源码如下
*/ final class UnreleasableByteBuf extends WrappedByteBuf { private SwappedByteBuf swappedBuf; UnreleasableByteBuf(ByteBuf buf) { super(buf instanceof UnreleasableByteBuf ? buf.unwrap() : buf); } @Override public ByteBuf order(ByteOrder endianness) { if (endianness == null) { throw new NullPointerException("endianness"); } if (endianness == order()) { return this; } SwappedByteBuf swappedBuf = this.swappedBuf; if (swappedBuf == null) { this.swappedBuf = swappedBuf = new SwappedByteBuf(this); } return swappedBuf; } @Override public ByteBuf asReadOnly() { return buf.isReadOnly() ? this : new UnreleasableByteBuf(buf.asReadOnly()); } ...