📄 decoratorpattern.htm
字号:
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<link rel="stylesheet" href="css/stdlayout.css" type="text/css">
<link rel="stylesheet" href="css/print.css" type="text/css">
<meta content="text/html; charset=gb2312" http-equiv="content-type">
<title>Decorator 模式</title>
</head>
<body>
<h3><a href="http://caterpillar.onlyfun.net/GossipCN/index.html">From
Gossip@caterpillar</a></h3>
<h1><a href="CppGossip.html">Design Pattern: Decorator 模式</a></h1>
在Java
Swing中的JTextArea元件预设并没有卷轴,因为设计人员认为卷轴的功能并不是一定需要的,而决定让程式人员可以动态选择是否增加卷轴功能,卷
轴的功能是由JScrollPane元件提供,如果您要加入一个具有卷轴功能的JTextArea,您可以如下进行设计:<br>
<div style="margin-left: 40px;"><span style="font-weight: bold; font-family: Courier New,Courier,monospace;">JTextArea textArea = new JTextArea();</span><br style="font-weight: bold; font-family: Courier New,Courier,monospace;">
<span style="font-weight: bold; font-family: Courier New,Courier,monospace;">JScrollPane scrollPane = new JScrollPane(textArea);</span><br>
</div>
<br>
JScrollPane对JTextArea即是个容器,而它对JFrame来说又是个元件,可以如下这般将之加入JFrame中:<br>
<div style="margin-left: 40px;"><span style="font-weight: bold; font-family: Courier New,Courier,monospace;">getContentPane().add(scrollPane);</span><br>
</div>
<br>
像这样动态的为JTextArea加入功能的方法,我们可以使用Decorator模式来组织结构,您可以动态的为一个物件加入一些功能(像是为
JTextArea加上卷轴),而又不用修改JTextArea的功能。对JTextArea来说,JScrollPane就好像是一个卷轴外框,直接套
在JTextArea上作装饰,就好比您在照片上加上一个相框的意思。<br>
<br>
先以上面这个例子来说明Decorator模式的一个实例:<br>
<div style="text-align: center;"><img style="width: 455px; height: 255px;" alt="Decorator" title="Decorator" src="images/decorator-1.jpg"><br>
</div>
<br>
如上图所示的,无论是TextView或是Decorator类别,它们都是VisualComponent的一个子类,也就是说它们都是一个可视元件,
而Decorator类又聚合了VisualComponent,所以又可以当作TextView容器,ScrollDecorator类别实作了
Decorator类,它可能是这样设计的:<br>
<div style="margin-left: 40px;"><span style="font-weight: bold; font-family: Courier New,Courier,monospace;">public abstract class Decorator extends VisualComponent {</span><br style="font-weight: bold; font-family: Courier New,Courier,monospace;">
<span style="font-weight: bold; font-family: Courier New,Courier,monospace;"> protected VisualComponent component;</span><br style="font-weight: bold; font-family: Courier New,Courier,monospace;">
<br style="font-weight: bold; font-family: Courier New,Courier,monospace;">
<span style="font-weight: bold; font-family: Courier New,Courier,monospace;"> public Decorator(VisualComponent component) {</span><br style="font-weight: bold; font-family: Courier New,Courier,monospace;">
<span style="font-weight: bold; font-family: Courier New,Courier,monospace;"> this.component = component;</span><br style="font-weight: bold; font-family: Courier New,Courier,monospace;">
<span style="font-weight: bold; font-family: Courier New,Courier,monospace;"> }</span><br style="font-weight: bold; font-family: Courier New,Courier,monospace;">
<br style="font-weight: bold; font-family: Courier New,Courier,monospace;">
<span style="font-weight: bold; font-family: Courier New,Courier,monospace;"> public void draw() {</span><br style="font-weight: bold; font-family: Courier New,Courier,monospace;">
<span style="font-weight: bold; font-family: Courier New,Courier,monospace;"> component.draw();</span><br style="font-weight: bold; font-family: Courier New,Courier,monospace;">
<span style="font-weight: bold; font-family: Courier New,Courier,monospace;"> }</span><br style="font-weight: bold; font-family: Courier New,Courier,monospace;">
<span style="font-weight: bold; font-family: Courier New,Courier,monospace;">}</span><br style="font-weight: bold; font-family: Courier New,Courier,monospace;">
<br style="font-weight: bold; font-family: Courier New,Courier,monospace;">
<span style="font-weight: bold; font-family: Courier New,Courier,monospace;">public class ScrollDecorator extends Decorator {</span><br style="font-weight: bold; font-family: Courier New,Courier,monospace;">
<span style="font-weight: bold; font-family: Courier New,Courier,monospace;"> public ScrollDecorator(VisualComponent component) {</span><br style="font-weight: bold; font-family: Courier New,Courier,monospace;">
<span style="font-weight: bold; font-family: Courier New,Courier,monospace;"> super(component);</span><br style="font-weight: bold; font-family: Courier New,Courier,monospace;">
<span style="font-weight: bold; font-family: Courier New,Courier,monospace;"> }</span><br style="font-weight: bold; font-family: Courier New,Courier,monospace;">
<br style="font-weight: bold; font-family: Courier New,Courier,monospace;">
<span style="font-weight: bold; font-family: Courier New,Courier,monospace;"> public void draw() {</span><br style="font-weight: bold; font-family: Courier New,Courier,monospace;">
<span style="font-weight: bold; font-family: Courier New,Courier,monospace;"> super.draw();</span><br style="font-weight: bold; font-family: Courier New,Courier,monospace;">
<span style="font-weight: bold; font-family: Courier New,Courier,monospace;"> scrollTo();</span><br style="font-weight: bold; font-family: Courier New,Courier,monospace;">
<span style="font-weight: bold; font-family: Courier New,Courier,monospace;"> }</span><br style="font-weight: bold; font-family: Courier New,Courier,monospace;">
<br style="font-weight: bold; font-family: Courier New,Courier,monospace;">
<span style="font-weight: bold; font-family: Courier New,Courier,monospace;"> public void scrollTo() {</span><br style="font-weight: bold; font-family: Courier New,Courier,monospace;">
<span style="font-weight: bold; font-family: Courier New,Courier,monospace;"> // ....</span><br style="font-weight: bold; font-family: Courier New,Courier,monospace;">
<span style="font-weight: bold; font-family: Courier New,Courier,monospace;"> }</span><br style="font-weight: bold; font-family: Courier New,Courier,monospace;">
<span style="font-weight: bold; font-family: Courier New,Courier,monospace;">}</span><br>
</div>
<br>
要将新功能套用至TextView上,可以这样设计:<br>
<div style="margin-left: 40px;"><span style="font-weight: bold; font-family: Courier New,Courier,monospace;">ScrollDecorator scrollDecorator = </span><br style="font-weight: bold; font-family: Courier New,Courier,monospace;">
<span style="font-weight: bold; font-family: Courier New,Courier,monospace;">
new ScrollDecorator(new TextView());</span><br>
</div>
<br>
super.draw()会先呼叫component也就是TextView物件的draw()方法先绘制TextView,然后再进行
ScrollPanel的scrollTo(),也就是卷动的方法。在图中也表示了一个BorderDecorator,它可能是这样设计的:<br>
<div style="margin-left: 40px;"><span style="font-weight: bold; font-family: Courier New,Courier,monospace;">public class BorderDecorator extends Decorator {</span><br style="font-weight: bold; font-family: Courier New,Courier,monospace;">
<span style="font-weight: bold; font-family: Courier New,Courier,monospace;"> public BorderDecorator(VisualComponent component) {</span><br style="font-weight: bold; font-family: Courier New,Courier,monospace;">
<span style="font-weight: bold; font-family: Courier New,Courier,monospace;"> super(component);</span><br style="font-weight: bold; font-family: Courier New,Courier,monospace;">
<span style="font-weight: bold; font-family: Courier New,Courier,monospace;"> }</span><br style="font-weight: bold; font-family: Courier New,Courier,monospace;">
<br style="font-weight: bold; font-family: Courier New,Courier,monospace;">
<span style="font-weight: bold; font-family: Courier New,Courier,monospace;"> public void draw() {</span><br style="font-weight: bold; font-family: Courier New,Courier,monospace;">
<span style="font-weight: bold; font-family: Courier New,Courier,monospace;"> super.draw();</span><br style="font-weight: bold; font-family: Courier New,Courier,monospace;">
<span style="font-weight: bold; font-family: Courier New,Courier,monospace;"> drawBorder();</span><br style="font-weight: bold; font-family: Courier New,Courier,monospace;">
<span style="font-weight: bold; font-family: Courier New,Courier,monospace;"> }</span><br style="font-weight: bold; font-family: Courier New,Courier,monospace;">
<br style="font-weight: bold; font-family: Courier New,Courier,monospace;">
<span style="font-weight: bold; font-family: Courier New,Courier,monospace;"> public void drawBorder() {</span><br style="font-weight: bold; font-family: Courier New,Courier,monospace;">
<span style="font-weight: bold; font-family: Courier New,Courier,monospace;"> // ....</span><br style="font-weight: bold; font-family: Courier New,Courier,monospace;">
<span style="font-weight: bold; font-family: Courier New,Courier,monospace;"> }</span><br style="font-weight: bold; font-family: Courier New,Courier,monospace;">
<span style="font-weight: bold; font-family: Courier New,Courier,monospace;">}</span><br>
</div>
<br>
要将ScrollDecorator与BorderDecorator加至TextView上,我们可以这样设计:<br>
<div style="margin-left: 40px;"><span style="font-weight: bold; font-family: Courier New,Courier,monospace;">BorderDecorator borderDecorator =</span><br style="font-weight: bold; font-family: Courier New,Courier,monospace;">
<span style="font-weight: bold; font-family: Courier New,Courier,monospace;"> new BorderDecorator(</span><br style="font-weight: bold; font-family: Courier New,Courier,monospace;">
<span style="font-weight: bold; font-family: Courier New,Courier,monospace;"> new ScrollDecorator(new TextView()));</span><span style="font-weight: bold; font-family: Courier New,Courier,monospace;"></span><br>
</div>
<br>
所以当BorderDecorator调用draw()方法时,它会先调用ScrollDecorator的draw()方法,而 ScrollDecorator的draw()方法又会先调用TextView的draw()方法,所以绘制的顺序变成:<br>
<div style="margin-left: 40px;"><span style="font-weight: bold; font-family: Courier New,Courier,monospace;">TextDraw.draw();</span><br style="font-weight: bold; font-family: Courier New,Courier,monospace;">
<span style="font-weight: bold; font-family: Courier New,Courier,monospace;">ScrollDecorator.scrollTo();</span><br style="font-weight: bold; font-family: Courier New,Courier,monospace;">
<span style="font-weight: bold; font-family: Courier New,Courier,monospace;">BorderDecorator.drawBorder();</span><br style="font-weight: bold; font-family: Courier New,Courier,monospace;">
<span style="font-weight: bold; font-family: Courier New,Courier,monospace;"></span><br>
</div>
下图为物件之间的调用关系:<br>
<div style="text-align: center;"><img style="width: 403px; height: 71px;" alt="Decorator" title="Decorator" src="images/decorator-2.jpg"><br>
</div>
<br>
Decorator模式的 UML 结构图如下所示:<br>
<div style="text-align: center;"><img style="width: 486px; height: 259px;" alt="Decorator" title="Decorator" src="images/decorator-3.jpg"><br>
</div>
<br>
在Gof的书中指出另一个范例,它设计一个Stream抽象类,而有一个StreamDecorator类,Stream的子类有处理记忆体串流的
MemoryStream与FileStream,有各种方法可以处理串流,也许只是单纯的处理字元,也许会进行压缩,也许会进行字元转换,最基本的处理
可能是处理字元,而字元压缩被视为额外的功能,这个时候我们可以使用装饰模式,在需要的时候为Stream物件加上必要的功能,事实上在java.io中
的许多输入输出物件,就是采取这样的设计。<br>
<br>
</body>
</html>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -