给对象添加新功能时,并不是在对象类中直接添加,而是在装饰器类中添加。
在装饰类中添加新功能,你可以增强原先对象的方法,也可以给对象新增一个方法。
假设要给人类添加开炮功能。
但由于这是人类,咱们不能通过继承直接给人类添加开炮功能;
所以我们就得通过组合,将机器和人类组合起来、通过变相实现人类可以开炮。
这个机器就是装饰器。
菜鸟教程的例子都将对象和装饰器进行了抽象处理,实现了可替换对象和装饰器的实现类。
菜鸟教程原例子
个人觉得这样理解装饰器太绕了,下面的例子就只保留了对象和装饰器。
定义一个圆的对象
public class Circle{
@Override
public void draw() {
System.out.println("Shape: Circle");
}
}
新增setRedBorder方法去设置红色边框。
public class RedCircleDecorator{
private Circle c;
public RedCircleDecorator(Circle c) {
this.c = c;
}
@Override
public void draw() {
decoratedShape.draw();
setRedBorder(decoratedShape);
}
private void setRedBorder(Circle decoratedShape){
System.out.println("Border Color: Red");
}
}
但我觉这个菜鸟这个例子并不能把装饰器模式特点表现出来。
因setRedBorder是私有,并且只是把原先draw方法进行了增强。
这样的话,代理模式也能实现,代理模式也能增强原有的方法,所以这里并不能把装饰器模式特点表现出来。
所以我改了一下。
public class ColorCircleDecorator{
private Circle c;
public RedCircleDecorator(Circle c) {
this.c = c;
}
@Override
public void draw() {
decoratedShape.draw();
System.out.println("画了个普通的圆");
}
public void drawRedCircle(Circle decoratedShape){
decoratedShape.draw();
System.out.println("画了个红色的圆");
}
public void drawBlueCircle(Circle decoratedShape){
decoratedShape.draw();
System.out.println("画了个蓝色的圆");
}
}
这个例子保留了原先的draw功能,又新增了drawRedCircle和drawBlueCircle功能。
包装类也运用了装饰器模式。
将基本类型 转 包装类 的同时,还提供各种转换类型的功能。
OutputStreamWriter同时运用了装饰器模式+适配器模式。
这里我们拿装饰器部分来讲。
FileOutputStream fos = new FileOutputStream(new File("Y:/学习资料.md"));
OutputStreamWriter osw = new OutputStreamWriter(fos);
osw.append("新资料xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
原本FileOutputStream 是原本没有append功能的,
而在中OutputStreamWriter 添加append功能。
源码:
public class OutputStreamWriter extends Writer {
private final StreamEncoder se;
public OutputStreamWriter(OutputStream out) {
super(out);
se = StreamEncoder.forOutputStreamWriter(out, lockFor(this),
out instanceof PrintStream ps ? ps.charset() : Charset.defaultCharset());
}
@Override
public Writer append(CharSequence csq) throws IOException {
if (csq instanceof CharBuffer) {
se.write((CharBuffer) csq);
} else {
se.write(String.valueOf(csq));
}
return this;
}
}
可以看到虽然OutputStreamWriter 重写了append方法。
但构造器里OutputStream又被新的装饰器StreamEncoder接收。
而StreamEncoder类就已经通过继承Writer 增加了append方法。
public final class StreamEncoder extends Writer {
private final OutputStream out;
private StreamEncoder(OutputStream out, Object lock, CharsetEncoder enc) {
super(lock);
this.out = out;
this.ch = null;
this.cs = enc.charset();
this.encoder = enc;
this.bb = ByteBuffer.allocate(INITIAL_BYTE_BUFFER_CAPACITY);
this.maxBufferCapacity = MAX_BYTE_BUFFER_CAPACITY;
}
public static StreamEncoder forOutputStreamWriter(OutputStream out, Object lock, Charset cs) {
return new StreamEncoder(out, lock, cs);
}
}
BeanWrapperImpl类是对BeanWrapper接口的默认实现,它包装了一个bean对象,缓存了bean的内省结果,并可以访问bean的属性、设置bean的属性值。
BeanWrapperImpl功能还挺复杂的,大家可以自行去看源码,我就不贴出来了。
HttpHeadResponseDecorator 给ServerHttpResponse 添加了writeWith、writeAndFlushWith的功能。
public class HttpHeadResponseDecorator extends ServerHttpResponseDecorator {
public HttpHeadResponseDecorator(ServerHttpResponse delegate) {
super(delegate);
}
public final Mono<Void> writeWith(Publisher<? extends DataBuffer> body) {
return this.shouldSetContentLength() && body instanceof Mono ? ((Mono)body).doOnSuccess((buffer) -> {
if (buffer != null) {
this.getHeaders().setContentLength((long)buffer.readableByteCount());
DataBufferUtils.release(buffer);
} else {
this.getHeaders().setContentLength(0L);
}
}).then() : Flux.from(body).doOnNext(DataBufferUtils::release).then();
}
private boolean shouldSetContentLength() {
return this.getHeaders().getFirst("Content-Length") == null && this.getHeaders().getFirst("Transfer-Encoding") == null;
}
public final Mono<Void> writeAndFlushWith(Publisher<? extends Publisher<? extends DataBuffer>> body) {
return this.setComplete();
}
}