阿里云-云小站(无限量代金券发放中)
【腾讯云】云服务器、云数据库、COS、CDN、短信等热卖云产品特惠抢购

装饰器

29次阅读
没有评论

共计 3055 个字符,预计需要花费 8 分钟才能阅读完成。

动态地给一个对象添加一些额外的职责。就增加功能来说,相比生成子类更为灵活。

装饰器(Decorator)模式,是一种在运行期动态给某个对象的实例增加功能的方法。

我们在 IO 的 Filter 模式一节中其实已经讲过装饰器模式了。在 Java 标准库中,InputStream是抽象类,FileInputStreamServletInputStreamSocket.getInputStream()这些 InputStream 都是最终数据源。

现在,如果要给不同的最终数据源增加缓冲功能、计算签名功能、加密解密功能,那么,3 个最终数据源、3 种功能一共需要 9 个子类。如果继续增加最终数据源,或者增加新功能,子类会爆炸式增长,这种设计方式显然是不可取的。

Decorator 模式的目的就是把一个一个的附加功能,用 Decorator 的方式给一层一层地累加到原始数据源上,最终,通过组合获得我们想要的功能。

例如:给 FileInputStream 增加缓冲和解压缩功能,用 Decorator 模式写出来如下:

// 创建原始的数据源:
InputStream fis = new FileInputStream("test.gz");
// 增加缓冲功能:
InputStream bis = new BufferedInputStream(fis);
// 增加解压缩功能:
InputStream gis = new GZIPInputStream(bis);

或者一次性写成这样:

InputStream input = new GZIPInputStream(// 第二层装饰
                        new BufferedInputStream(// 第一层装饰
                            new FileInputStream("test.gz") // 核心功能
                        ));

观察 BufferedInputStreamGZIPInputStream,它们实际上都是从 FilterInputStream 继承的,这个 FilterInputStream 就是一个抽象的 Decorator。我们用图把 Decorator 模式画出来如下:

             ┌───────────┐
             │ Component │
             └───────────┘
                   ▲
      ┌────────────┼─────────────────┐
      │            │                 │
┌───────────┐┌───────────┐     ┌───────────┐
│ComponentA ││ComponentB │...  │ Decorator │
└───────────┘└───────────┘     └───────────┘
                                     ▲
                              ┌──────┴──────┐
                              │             │
                        ┌───────────┐ ┌───────────┐
                        │DecoratorA │ │DecoratorB │...
                        └───────────┘ └───────────┘

最顶层的 Component 是接口,对应到 IO 的就是 InputStream 这个抽象类。ComponentA、ComponentB 是实际的子类,对应到 IO 的就是 FileInputStreamServletInputStream 这些数据源。Decorator 是用于实现各个附加功能的抽象装饰器,对应到 IO 的就是 FilterInputStream。而从 Decorator 派生的就是一个一个的装饰器,它们每个都有独立的功能,对应到 IO 的就是BufferedInputStreamGZIPInputStream 等。

Decorator 模式有什么好处?它实际上把核心功能和附加功能给分开了。核心功能指 FileInputStream 这些真正读数据的源头,附加功能指加缓冲、压缩、解密这些功能。如果我们要新增核心功能,就增加 Component 的子类,例如ByteInputStream。如果我们要增加附加功能,就增加 Decorator 的子类,例如CipherInputStream。两部分都可以独立地扩展,而具体如何附加功能,由调用方自由组合,从而极大地增强了灵活性。

如果我们要自己设计完整的 Decorator 模式,应该如何设计?

我们还是举个栗子:假设我们需要渲染一个 HTML 的文本,但是文本还可以附加一些效果,比如加粗、变斜体、加下划线等。为了实现动态附加效果,可以采用 Decorator 模式。

首先,仍然需要定义顶层接口TextNode

public interface TextNode {// 设置 text:
    void setText(String text);
    // 获取 text:
    String getText();
}

对于核心节点,例如 <span>,它需要从TextNode 直接继承:

public class SpanNode implements TextNode {private String text;

    public void setText(String text) {this.text = text;
    }

    public String getText() {return "<span>" + text + "</span>";
    }
}

紧接着,为了实现 Decorator 模式,需要有一个抽象的 Decorator 类:

public abstract class NodeDecorator implements TextNode {protected final TextNode target;

    protected NodeDecorator(TextNode target) {this.target = target;
    }

    public void setText(String text) {this.target.setText(text);
    }
}

这个 NodeDecorator 类的核心是持有一个 TextNode,即将要把功能附加到的TextNode 实例。接下来就可以写一个加粗功能:

public class BoldDecorator extends NodeDecorator {public BoldDecorator(TextNode target) {super(target);
    }

    public String getText() {return "<b>" + target.getText() + "</b>";
    }
}

类似的,可以继续加 ItalicDecoratorUnderlineDecorator 等。客户端可以自由组合这些 Decorator:

TextNode n1 = new SpanNode();
TextNode n2 = new BoldDecorator(new UnderlineDecorator(new SpanNode()));
TextNode n3 = new ItalicDecorator(new BoldDecorator(new SpanNode()));
n1.setText("Hello");
n2.setText("Decorated");
n3.setText("World");
System.out.println(n1.getText());
// 输出 <span>Hello</span>

System.out.println(n2.getText());
// 输出 <b><u><span>Decorated</span></u></b>

System.out.println(n3.getText());
// 输出 <i><b><span>World</span></b></i>

练习

使用 Decorator 添加一个 <del> 标签表示删除。

下载练习

小结

使用 Decorator 模式,可以独立增加核心功能,也可以独立增加附加功能,二者互不影响;

可以在运行期动态地给核心功能增加任意个附加功能。

正文完
星哥说事-微信公众号
post-qrcode
 0
星锅
版权声明:本站原创文章,由 星锅 于2024-08-05发表,共计3055字。
转载说明:除特殊说明外本站文章皆由CC-4.0协议发布,转载请注明出处。
【腾讯云】推广者专属福利,新客户无门槛领取总价值高达2860元代金券,每种代金券限量500张,先到先得。
阿里云-最新活动爆款每日限量供应
评论(没有评论)
验证码
【腾讯云】云服务器、云数据库、COS、CDN、短信等云产品特惠热卖中