對象的樹結構
在面向對象的技術裡
對象的樹結構是一個強有力的工具
更是模式理論的一個重要的組成部分
需要應用到符合模式
裝飾模式和迭代子模式
《墨子
天志》說
庶人竭力從事
未得次己而為政
有士政之
士竭力從事
未得次己而為政
有將軍
大夫政之
將軍
大夫竭力從事
未得次己而為政
有三公
諸侯政之
三公
諸侯竭力聽治
未得次己而為政
有天子政之
天子未得次己而為政
有天政之
次
意為恣意
上面的話就是說
百姓有官吏管治
官吏由將軍和士大夫管治
將軍和士大夫由三公和諸侯管治
三公和諸侯由天子管治
天子由天管治
圖
墨子論責任和責任鏈的傳播
圖中有陰影的對象給出了一個可能的責任鏈選擇
當一個百姓提出要求時
此要求會傳達到
士
一級
再到
大夫
一級
進而傳到
諸侯
一級
天子
一級
最後到
天
一級
DHTML中的事件處理
浏覽器的DOM(Document Object Model)模型中的事件處理均采用責任鏈模式
本節首先考察Netscape浏覽器的DHTML的事件處理
然後再研究Internet Explorer的事件模型
Netscape的事件模型
Netscape的事件處理機制叫做
事件捕捉
(Event Capturing)
在事件捕捉機制裡面
一個事件是從DOM的最高一層向下傳播
也就是說
window對象是第一個接到事件的
然後是document對象
如此往下
事件的產生對象反而是最後一個接到事件的
如果要是一個對象捕獲某一個事件
只需要調用captureEvent()方法
如果要使一個對象把某一個事件向下傳而不處理此事件
只需要對此對象使用releaseEvents方法即可
下面考察一個簡單的事件捕獲和傳遞的例子
圖
一個Netscape的例子
在這個例子裡
有一個textbox和兩個button
一個叫做
Capture Event
單擊後會使網頁的click事件被捕捉
文字框中的計數會加一
另一個叫做
Release Event
單擊後會使網頁的click事件不被捕捉
使click事件被捕捉需要調用captureEvent()方法
而使click事件不被捕捉需要調用releaseEvent()方法
下面是具體的html和JavaScript代碼
代碼清單
JavaScript和HTML源代碼
顯然
一個事件可以在幾個不同的等級上得到處理
這是一個不純的責任鏈模式
Internet Explorer的事件模型
Internet Explorer處理事件的方式與Netscape既相似又不同
當一個事件發生在Internet Explorer所浏覽的網頁中時
Internet Explorer會使用DHTML的
Event Bubbling
即事件浮升機制處理此事件
Internet Explorer的DOM模型是html對象等級結構和事件處理機制
在DOM裡面
每一個html標示都是一個DOM對象
而每一個DOM對象都可以產生事先定義好的幾個事件中的一個(或幾個)
這樣的一個事件會首先發生在事件所屬的對象上
然後向上傳播
傳到此對象所屬的容器對象上
如此等等
因此
事件浮升機制恰恰是事件捕捉機制的相反面
在Event Bubbling機制裡面
產生事件的對象首先會收到事件
然後
事件會依照對象的等級結構向上傳播
比如一個DIV裡有一個Form
Form裡面又有一個Button
那麼當Button的onclick事件產生時
Form的onclick事件代碼就會被執行
然後
事件就會傳到DIV對象
如果DIV對象的onclick事件有任何代碼的話
這代碼就會被執行
然後事件繼續沿著DOM結構上行
如果要阻止事件繼續向上傳播
可以在事件鏈的任何一個節點上把cancelBubble性質設置成True即可
Internet Explorer 浏覽器幾乎為所有的 HTML 標識符都提供了事件句柄
因此Internet Explorer不需要captureEvents()方法和releaseEvents()方法來捕獲和釋放事件
下面的JavaScript語句指定了document對象的onclick事件的處理方法
document
onclick = functionName;
而下面的語句則停止了document對象對onclick事件的處理
document
onclick = null;
因為事件處理性質被賦值null
document便沒有任何的方法處理此事件
換言之
null值禁止了此對象的事件處理
這種方法可以用到任何的對象和任何的事件上面
當然這一做法不適用於Netscape
與Netscape中一樣
一個事件處理方法可以返還Boolean值
比如
單擊一個超鏈接標記符是否造成浏覽器跟進
取決於此超鏈接標記符的onclick事件是否返還true
為了顯示Internet Explorer中的事件浮升機制
本節特准備了下面的例子
一個Form裡面有一個Button
請見下圖
圖
一個Internet Explorer的例子
其HTML代碼請見下面
代碼清單
JavaScript和HTML源代碼
當myButton的onclick事件發生時
myButton的事件處理首先被激發
從而顯示出如下的對話窗
圖
myButton對象的事件處理被激發
然後事件會象氣泡一樣浮升到上一級的對象
即myForm對象上
myForm對象的事件處理給出下面的對話窗
圖
myFormn對象的事件處理被激發
這以後事件繼續浮升到更上一級的對象
即body上
這時
document對象的事件處理被激發
並給出下面的對象窗
圖
document對象的事件處理被激發
這就是事件浮升(Event Bubbling)機制
顯然
這三級對象組成一個責任鏈
而事件便是命令或請求
當事件沿著責任鏈傳播時
責任鏈上的對象可以選擇處理或不處理此事件
不論事件在某一個等級上是否得到處理
事件都可以停止上浮或繼續上浮
這是不純的責任鏈模式
責任鏈模式與其它模式的關系
責任鏈模式與以下的設計模式相關
復合模式(Composite Pattern) 當責任鏈模式中的對象鏈屬於一個較大的結構時
這個較大的結構可能符合復合模式
命令模式(Command Pattern) 責任鏈模式使一個特定的請求接收對象對請求或命令的執行變得不確定
而命令模式使得一個特定的對象對一個命令的執行變得明顯和確定
模版方法模式(Template Method) 當組成責任鏈的處理者對象是按照復合模式組成一個較大的結構的責成部分的話
模版方法模式經常用來組織單個的對象的行為
問答題
第一題
在稱為
拱豬
的紙牌游戲中
四個參加者中由
豬
牌的
可以選擇一個時機放出這張
豬
牌
豬
牌放出後
四個人中的一個會不可避免地拿到這張
豬
牌
請使用責任鏈模式說明這一游戲
並給出UML結構圖
第二題
《墨子
迎敵祠》裡描守城軍隊的結構
城上步一甲
一戟
其贊三人
五步有伍長
十步有什長
百步有佰長
旁有大帥
中有大將
皆有司吏卒長
一個兵勇需要上級批准以便執行一項任務
他要向伍長請求批准
伍長如果有足夠的權限
便會批准或駁回請求
如果他沒有足夠的權限
便會向上級
即什長轉達這個請求
什長便會重復同樣的過程
直到大將那裡
一個請求最終會被批准或駁回
然後就會象下傳
直到傳回到發出請求的士兵手裡
有些請求會很快返回
有些則要經過較長的過程
請求到底由誰批准
事前並不知道
請求的處理者並不是固定的
有些軍官會晉升
轉業
或從別的單位轉過來
等等
請使用責任鏈模式解釋這個核准請求的結構
(本例子受到文獻[ALPERT
]裡
Chain of Responsibility
一節所給出的一個例子的啟發
)
第三題
王羲之在《蘭亭序》中寫道
有清流激湍
映帶左右
引以為流觞曲水
列坐其次
講的是大伙列坐水畔
隨水流放下帶羽毛的酒杯飲酒
遠道而來的酒杯流到誰的面前
誰就取而飲之
在這個活動中
參加者做成一排
面對著一條彎曲的小溪
侍者把酒杯盛滿酒
讓酒杯沿著小溪向下漂流
酒杯漂到一個參加者面前的時候
他可以選擇取酒飲之
也可以選擇讓酒杯漂向下家
假設每一杯酒最終都會被參加者中之一喝掉
那麼這個游戲是不是純的責任鏈模式?
問答題答案
第一題答案
這是一個純的責任鏈模式
首先
在
豬
牌放出之後
每個人都只能要麼躲過
豬
牌
要麼吃住
豬
牌
豬
牌便是責任鏈模式中的請求
四個人便是四個處理者對象
組成責任鏈
每一個參加者的行為不僅僅取決於他手中的牌
而且取決於他是否想得
豬
牌
一個想收全紅的人
可能會權力攬
豬
牌
一個不想收全紅的人
一般不想收
豬
牌
除非他想阻止別人收
豬
牌
因為一旦有人收全紅
另外三個人就會復出較大的代價
因此阻止別人收全紅的動機
會促使一個參與者主動收
豬
牌
有的時候
放出
豬
牌的人也會想要得
豬
牌而得不到
有的時候放出
豬
牌的人想要害人但卻害了自己
這就是說
到底是四個人中的哪一個人得到
豬
牌是完全動態決定的
系統的UML結構圖如下
圖
紙牌游戲
拱豬
的UML類圖
由於玩牌的時候
可能有四人位置的任意調換
或者有候補者在旁等待
一旦在任的玩家被淘汰
便可上任
這樣四個人組成的牌局是動態變化的
同時因為誰會拿到
豬
牌在每一局均會不同
因此誰會放出
豬
牌也是動態的
因此
責任鏈的組成和順序變不是一成不變的
而是動態的和變化的
第二題答案
墨子的守城部隊的等級結構可以用下面的對象圖表示
From:http://tw.wingwit.com/Article/program/Java/gj/201311/27325.html