?? decoratorpattern.htm
字號(hào):
<!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元件預(yù)設(shè)并沒(méi)有卷軸,因?yàn)樵O(shè)計(jì)人員認(rèn)為卷軸的功能并不是一定需要的,而決定讓程式人員可以動(dòng)態(tài)選擇是否增加卷軸功能,卷
軸的功能是由JScrollPane元件提供,如果您要加入一個(gè)具有卷軸功能的JTextArea,您可以如下進(jìn)行設(shè)計(jì):<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對(duì)JTextArea即是個(gè)容器,而它對(duì)JFrame來(lái)說(shuō)又是個(gè)元件,可以如下這般將之加入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>
像這樣動(dòng)態(tài)的為JTextArea加入功能的方法,我們可以使用Decorator模式來(lái)組織結(jié)構(gòu),您可以動(dòng)態(tài)的為一個(gè)物件加入一些功能(像是為
JTextArea加上卷軸),而又不用修改JTextArea的功能。對(duì)JTextArea來(lái)說(shuō),JScrollPane就好像是一個(gè)卷軸外框,直接套
在JTextArea上作裝飾,就好比您在照片上加上一個(gè)相框的意思。<br>
<br>
先以上面這個(gè)例子來(lái)說(shuō)明Decorator模式的一個(gè)實(shí)例:<br>
<div style="text-align: center;"><img style="width: 455px; height: 255px;" alt="Decorator" title="Decorator" src="images/decorator-1.jpg"><br>
</div>
<br>
如上圖所示的,無(wú)論是TextView或是Decorator類別,它們都是VisualComponent的一個(gè)子類,也就是說(shuō)它們都是一個(gè)可視元件,
而Decorator類又聚合了VisualComponent,所以又可以當(dāng)作TextView容器,ScrollDecorator類別實(shí)作了
Decorator類,它可能是這樣設(shè)計(jì)的:<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上,可以這樣設(shè)計(jì):<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()會(huì)先呼叫component也就是TextView物件的draw()方法先繪制TextView,然后再進(jìn)行
ScrollPanel的scrollTo(),也就是卷動(dòng)的方法。在圖中也表示了一個(gè)BorderDecorator,它可能是這樣設(shè)計(jì)的:<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上,我們可以這樣設(shè)計(jì):<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>
所以當(dāng)BorderDecorator調(diào)用draw()方法時(shí),它會(huì)先調(diào)用ScrollDecorator的draw()方法,而 ScrollDecorator的draw()方法又會(huì)先調(diào)用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>
下圖為物件之間的調(diào)用關(guān)系:<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 結(jié)構(gòu)圖如下所示:<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的書(shū)中指出另一個(gè)范例,它設(shè)計(jì)一個(gè)Stream抽象類,而有一個(gè)StreamDecorator類,Stream的子類有處理記憶體串流的
MemoryStream與FileStream,有各種方法可以處理串流,也許只是單純的處理字元,也許會(huì)進(jìn)行壓縮,也許會(huì)進(jìn)行字元轉(zhuǎn)換,最基本的處理
可能是處理字元,而字元壓縮被視為額外的功能,這個(gè)時(shí)候我們可以使用裝飾模式,在需要的時(shí)候?yàn)镾tream物件加上必要的功能,事實(shí)上在java.io中
的許多輸入輸出物件,就是采取這樣的設(shè)計(jì)。<br>
<br>
</body>
</html>
?? 快捷鍵說(shuō)明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號(hào)
Ctrl + =
減小字號(hào)
Ctrl + -