欧美三区_成人在线免费观看视频_欧美极品少妇xxxxⅹ免费视频_a级毛片免费播放_鲁一鲁中文字幕久久_亚洲一级特黄

(第Ⅲ部分 結(jié)構(gòu)型模式篇) 第10章 組合模式(Com

系統(tǒng) 1975 0
——.NET設(shè)計(jì)模式系列之十一
Terrylee 2006 3
概述
組合模式有時(shí)候又叫做部分 - 整體模式,它使我們樹型結(jié)構(gòu)的問題中,模糊了簡(jiǎn)單元素和復(fù)雜元素的概念,客戶程序可以向處理簡(jiǎn)單元素一樣來處理復(fù)雜元素,從而使得客戶程序與復(fù)雜元素的內(nèi)部結(jié)構(gòu)解耦。
意圖
將對(duì)象組合成樹形結(jié)構(gòu)以表示“部分 - 整體”的層次結(jié)構(gòu)。 Composite 模式使得用戶對(duì)單個(gè)對(duì)象和組合對(duì)象的使用具有一致性。 [GOF 《設(shè)計(jì)模式》 ]
結(jié)構(gòu)圖
1 Composite 模式結(jié)構(gòu)圖
生活中的例子
組合模式將對(duì)象組合成樹形結(jié)構(gòu)以表示 " 部分 - 整體 " 的層次結(jié)構(gòu)。讓用戶一致地使用單個(gè)對(duì)象和組合對(duì)象。雖然例子抽象一些,但是算術(shù)表達(dá)式確實(shí)是組合的例子。算術(shù)表達(dá)式包括操作數(shù)、操作符和另一個(gè)操作數(shù)。操作數(shù)可以是數(shù)字,也可以是另一個(gè)表達(dá)式。這樣, 2+3 和( 2+3 + 4*6 )都是合法的表達(dá)式。
2 使用算術(shù)表達(dá)式例子的 Composite 模式對(duì)象圖
組合模式解說
這里我們用繪圖這個(gè)例子來說明 Composite 模式,通過一些基本圖像元素(直線、圓等)以及一些復(fù)合圖像元素(由基本圖像元素組合而成)構(gòu)建復(fù)雜的圖形樹。在設(shè)計(jì)中我們對(duì)每一個(gè)對(duì)象都配備一個(gè) Draw() 方法,在調(diào)用時(shí),會(huì)顯示相關(guān)的圖形。可以看到,這里復(fù)合圖像元素它在充當(dāng)對(duì)象的同時(shí),又是那些基本圖像元素的一個(gè)容器。先看一下基本的類結(jié)構(gòu)圖:
3
圖中橙色的區(qū)域表示的是復(fù)合圖像元素。示意性代碼:
而其他作為樹枝構(gòu)件,實(shí)現(xiàn)代碼如下: 現(xiàn)在我們要對(duì)該圖像元素進(jìn)行處理:在客戶端程序中,需要判斷返回對(duì)象的具體類型到底是基本圖像元素,還是復(fù)合圖像元素。如果是復(fù)合圖像元素,我們將要用遞歸去處理,然而這種處理的結(jié)果卻增加了客戶端程序與復(fù)雜圖像元素內(nèi)部結(jié)構(gòu)之間的依賴,那么我們?nèi)绾稳ソ怦钸@種關(guān)系呢?我們希望的是客戶程序可以像處理基本圖像元素一樣來處理復(fù)合圖像元素,這就要引入 Composite 模式了,需要把對(duì)于子對(duì)象的管理工作交給復(fù)合圖像元素,為了進(jìn)行子對(duì)象的管理,它必須提供必要的 Add() Remove() 等方法,類結(jié)構(gòu)圖如下:
public abstract class Graphics
{
protected string _name;

public Graphics( string name)
{
this ._name = name;
}

public abstract void Draw();
}


public class Picture:Graphics
{
public Picture( string name)
:
base (name)
{}
public override void Draw()
{
//
}


public ArrayListGetChilds()
{
// 返回所有的子對(duì)象
}

}
public class Line:Graphics
{
public Line( string name)
:
base (name)
{}

public override void Draw()
{
Console.WriteLine(
" Drawa " + _name.ToString());
}

}


public class Circle:Graphics
{
public Circle( string name)
:
base (name)
{}

public override void Draw()
{
Console.WriteLine(
" Drawa " + _name.ToString());
}

}


public class Rectangle:Graphics
{
public Rectangle( string name)
:
base (name)
{}

public override void Draw()
{
Console.WriteLine(
" Drawa " + _name.ToString());
}

}
圖4
示意性代碼:
這樣引入 Composite 模式后,客戶端程序不再依賴于復(fù)合圖像元素的內(nèi)部實(shí)現(xiàn)了。然而,我們程序中仍然存在著問題,因?yàn)? Line Rectangle Circle 已經(jīng)沒有了子對(duì)象,它是一個(gè)基本圖像元素,因此 Add() Remove() 的方法對(duì)于它來說沒有任何意義,而且把這種錯(cuò)誤不會(huì)在編譯的時(shí)候報(bào)錯(cuò),把錯(cuò)誤放在了運(yùn)行期,我們希望能夠捕獲到這類錯(cuò)誤,并加以處理,稍微改進(jìn)一下我們的程序: 這樣改進(jìn)以后,我們可以捕獲可能出現(xiàn)的錯(cuò)誤,做進(jìn)一步的處理。上面的這種實(shí)現(xiàn)方法屬于透明式的 Composite 模式,如果我們想要更安全的一種做法,就需要把管理子對(duì)象的方法聲明在樹枝構(gòu)件 Picture 類里面,這樣如果葉子節(jié)點(diǎn) Line Rectangle Circle 使用這些方法時(shí),在編譯期就會(huì)出錯(cuò),看一下類結(jié)構(gòu)圖:
public abstract class Graphics
{
protected string _name;

public Graphics( string name)
{
this ._name = name;
}

public abstract void Draw();
public abstract void Add();
public abstract void Remove();
}


public class Picture:Graphics
{
protected ArrayListpicList = new ArrayList();

public Picture( string name)
:
base (name)
{}
public override void Draw()
{
Console.WriteLine(
" Drawa " + _name.ToString());

foreach (Graphicsg in picList)
{
g.Draw();
}

}


public override void Add(Graphicsg)
{
picList.Add(g);
}

public override void Remove(Graphicsg)
{
picList.Remove(g);
}

}


public class Line:Graphics
{
public Line( string name)
:
base (name)
{}

public override void Draw()
{
Console.WriteLine(
" Drawa " + _name.ToString());
}

public override void Add(Graphicsg)
{}
public override void Remove(Graphicsg)
{}
}


public class Circle:Graphics
{
public Circle( string name)
:
base (name)
{}

public override void Draw()
{
Console.WriteLine(
" Drawa " + _name.ToString());
}

public override void Add(Graphicsg)
{}
public override void Remove(Graphicsg)
{}
}


public class Rectangle:Graphics
{
public Rectangle( string name)
:
base (name)
{}

public override void Draw()
{
Console.WriteLine(
" Drawa " + _name.ToString());
}

public override void Add(Graphicsg)
{}
public override void Remove(Graphicsg)
{}
}
public class Line:Graphics
{
public Line( string name)
:
base (name)
{}

public override void Draw()
{
Console.WriteLine(
" Drawa " + _name.ToString());
}

public override void Add(Graphicsg)
{
// 拋出一個(gè)我們自定義的異常
}

public override void Remove(Graphicsg)
{
// 拋出一個(gè)我們自定義的異常
}

}
圖5
示意性代碼:
這種方式屬于安全式的 Composite 模式,在這種方式下,雖然避免了前面所討論的錯(cuò)誤,但是它也使得葉子節(jié)點(diǎn)和樹枝構(gòu)件具有不一樣的接口。這種方式和透明式的 Composite 各有優(yōu)劣,具體使用哪一個(gè),需要根據(jù)問題的實(shí)際情況而定。通過 Composite 模式,客戶程序在調(diào)用 Draw() 的時(shí)候不用再去判斷復(fù)雜圖像元素中的子對(duì)象到底是基本圖像元素,還是復(fù)雜圖像元素,看一下簡(jiǎn)單的客戶端調(diào)用: .NET 中的組合模式
public abstract class Graphics
{
protected string _name;

public Graphics( string name)
{
this ._name = name;
}

public abstract void Draw();
}


public class Picture:Graphics
{
protected ArrayListpicList = new ArrayList();

public Picture( string name)
:
base (name)
{}
public override void Draw()
{
Console.WriteLine(
" Drawa " + _name.ToString());

foreach (Graphicsg in picList)
{
g.Draw();
}

}


public void Add(Graphicsg)
{
picList.Add(g);
}

public void Remove(Graphicsg)
{
picList.Remove(g);
}

}


public class Line:Graphics
{
public Line( string name)
:
base (name)
{}

public override void Draw()
{
Console.WriteLine(
" Drawa " + _name.ToString());
}

}


public class Circle:Graphics
{
public Circle( string name)
:
base (name)
{}

public override void Draw()
{
Console.WriteLine(
" Drawa " + _name.ToString());
}

}


public class Rectangle:Graphics
{
public Rectangle( string name)
:
base (name)
{}

public override void Draw()
{
Console.WriteLine(
" Drawa " + _name.ToString());
}

}
public class App
{
public static void Main()
{
Pictureroot
= new Picture( " Root " );

root.Add(
new Line( " Line " ));
root.Add(
new Circle( " Circle " ));

Rectangler
= new Rectangle( " Rectangle " );
root.Add(r);

root.Draw();
}

}
如果有人用過 Enterprise Library2.0 ,一定在源程序中看到了一個(gè)叫做 ObjectBuilder 的程序集,顧名思義,它是用來負(fù)責(zé)對(duì)象的創(chuàng)建工作的,而在 ObjectBuilder 中,有一個(gè)被稱為定位器的東西,通過定位器,可以很容易的找到對(duì)象, 它的結(jié)構(gòu)采用鏈表結(jié)構(gòu),每一個(gè)節(jié)點(diǎn)是一個(gè)鍵值對(duì),用來標(biāo)識(shí)對(duì)象的唯一性,使得對(duì)象不會(huì)被重復(fù)創(chuàng)建。定位器的鏈表結(jié)構(gòu)采用可枚舉的接口類來實(shí)現(xiàn),這樣我們可以通過一個(gè)迭代器來遍歷這個(gè)鏈表。同時(shí)多個(gè)定位器也被串成一個(gè)鏈表。具體地說就是多個(gè)定位器組成一個(gè)鏈表,表中的每一個(gè)節(jié)點(diǎn)是一個(gè)定位器,定位器本身又是一個(gè)鏈表,表中保存著多個(gè)由鍵值對(duì)組成的對(duì)象的節(jié)點(diǎn)。所以這是一個(gè)典型的Composite模式的例子,來看它的結(jié)構(gòu)圖:
(第Ⅲ部分 結(jié)構(gòu)型模式篇) 第10章 組合模式(Composite Pattern)
圖6
正如我們?cè)趫D中所看到的, IReadableLocator 定義了最上層的定位器接口方法,它基本上具備了定位器的大部分功能。
部分代碼:
一個(gè)抽象基類 ReadableLocator 用來實(shí)現(xiàn)這個(gè)接口的公共方法。兩個(gè)主要的方法實(shí)現(xiàn)代碼如下: 可以看到,在FindBy方法里面,循環(huán)調(diào)用了 FindInLocator 方法, 如果查詢選項(xiàng)是只查找當(dāng)前定位器,那么循環(huán)終止,否則沿著定位器的父定位器繼續(xù)向上查找。FindInLocator方法就是遍歷定位器,然后把找到的對(duì)象存入一個(gè)臨時(shí)的定位器。最后返回一個(gè)只讀定位器的新的實(shí)例。
public interface IReadableLocator:IEnumerable < KeyValuePair < object , object >>
{
// 返回定位器中節(jié)點(diǎn)的數(shù)量
int Count { get ;}

// 一個(gè)指向父節(jié)點(diǎn)的引用
IReadableLocatorParentLocator { get ;}

// 表示定位器是否只讀
bool ReadOnly { get ;}

// 查詢定位器中是否已經(jīng)存在指定鍵值的對(duì)象
bool Contains( object key);

// 查詢定位器中是否已經(jīng)存在指定鍵值的對(duì)象,根據(jù)給出的搜索選項(xiàng),表示是否要向上回溯繼續(xù)尋找。
bool Contains( object key,SearchModeoptions);

// 使用謂詞操作來查找包含給定對(duì)象的定位器
IReadableLocatorFindBy(Predicate < KeyValuePair < object , object >> predicate);

// 根據(jù)是否回溯的選項(xiàng),使用謂詞操作來查找包含對(duì)象的定位器
IReadableLocatorFindBy(SearchModeoptions,Predicate < KeyValuePair < object , object >> predicate);

// 從定位器中獲取一個(gè)指定類型的對(duì)象
TItemGet < TItem > ();

// 從定位其中獲取一個(gè)指定鍵值的對(duì)象
TItemGet < TItem > ( object key);

// 根據(jù)選項(xiàng)條件,從定位其中獲取一個(gè)指定類型的對(duì)象
TItemGet < TItem > ( object key,SearchModeoptions);

// 給定對(duì)象鍵值獲取對(duì)象的非泛型重載方法
object Get( object key);

// 給定對(duì)象鍵值帶搜索條件的非泛型重載方法
object Get( object key,SearchModeoptions);
}
public abstract class ReadableLocator:IReadableLocator
{
/**/ /// <summary>
/// 查找定位器,最后返回一個(gè)只讀定位器的實(shí)例
/// </summary>

public IReadableLocatorFindBy(SearchModeoptions,Predicate < KeyValuePair < object , object >> predicate)
{
if (predicate == null )
throw new ArgumentNullException( " predicate " );
if ( ! Enum.IsDefined( typeof (SearchMode),options))
throw new ArgumentException(Properties.Resources.InvalidEnumerationValue, " options " );

Locatorresults
= new Locator();
IReadableLocatorcurrentLocator
= this ;

while (currentLocator != null )
{
FindInLocator(predicate,results,currentLocator);
currentLocator
= options == SearchMode.Local ? null :currentLocator.ParentLocator;
}


return new ReadOnlyLocator(results);
}


/**/ /// <summary>
/// 遍歷定位器
/// </summary>

private void FindInLocator(Predicate < KeyValuePair < object , object >> predicate,Locatorresults,
IReadableLocatorcurrentLocator)
{
foreach (KeyValuePair < object , object > kvp in currentLocator)
{
if ( ! results.Contains(kvp.Key) && predicate(kvp))
{
results.Add(kvp.Key,kvp.Value);
}

}

}

}
從這個(gè)抽象基類中派生出一個(gè)具體類和一個(gè)抽象類,一個(gè)具體類是只讀定位器( ReadOnlyLocator ),只讀定位器實(shí)現(xiàn)抽象基類沒有實(shí)現(xiàn)的方法,它封裝了一個(gè)實(shí)現(xiàn)了 IReadableLocator 接口的定位器,然后屏蔽內(nèi)部定位器的寫入接口方法。另一個(gè)繼承的是讀寫定位器抽象類ReadWriteLocator,為了實(shí)現(xiàn)對(duì)定位器的寫入和刪除,這里定義了一個(gè)對(duì) IReadableLocator 接口擴(kuò)展的接口叫做 IReadWriteLocator ,在這個(gè)接口里面提供了實(shí)現(xiàn)定位器的操作:
(第Ⅲ部分 結(jié)構(gòu)型模式篇) 第10章 組合模式(Composite Pattern)
圖7
實(shí)現(xiàn)代碼如下:
public interface IReadWriteLocator:IReadableLocator
{
// 保存對(duì)象到定位器
void Add( object key, object value);

// 從定位器中刪除一個(gè)對(duì)象,如果成功返回真,否則返回假
bool Remove( object key);
}
從ReadWirteLocator派生的具體類是Locator類,Locator類必須實(shí)現(xiàn)一個(gè)定位器的全部功能,現(xiàn)在我們所看到的Locator它已經(jīng)具有了管理定位器的功能,同時(shí)他還應(yīng)該具有存儲(chǔ)的結(jié)構(gòu),這個(gè)結(jié)構(gòu)是通過一個(gè)WeakRefDictionary類來實(shí)現(xiàn)的,這里就不介紹了。[關(guān)于定位器的介紹參考了 niwalker 的Blog]
效果及實(shí)現(xiàn)要點(diǎn)
1 Composite 模式采用樹形結(jié)構(gòu)來實(shí)現(xiàn)普遍存在的對(duì)象容器,從而將“一對(duì)多”的關(guān)系轉(zhuǎn)化“一對(duì)一”的關(guān)系,使得客戶代碼可以一致地處理對(duì)象和對(duì)象容器,無需關(guān)心處理的是單個(gè)的對(duì)象,還是組合的對(duì)象容器。
2 .將“客戶代碼與復(fù)雜的對(duì)象容器結(jié)構(gòu)”解耦是 Composite 模式的核心思想,解耦之后,客戶代碼將與純粹的抽象接口——而非對(duì)象容器的復(fù)內(nèi)部實(shí)現(xiàn)結(jié)構(gòu)——發(fā)生依賴關(guān)系,從而更能“應(yīng)對(duì)變化”。
3 Composite 模式中,是將“ Add Remove 等和對(duì)象容器相關(guān)的方法”定義在“表示抽象對(duì)象的 Component 類”中,還是將其定義在“表示對(duì)象容器的 Composite 類”中,是一個(gè)關(guān)乎“透明性”和“安全性”的兩難問題,需要仔細(xì)權(quán)衡。這里有可能違背面向?qū)ο蟮摹皢我宦氊?zé)原則”,但是對(duì)于這種特殊結(jié)構(gòu),這又是必須付出的代價(jià)。 ASP.NET 控件的實(shí)現(xiàn)在這方面為我們提供了一個(gè)很好的示范。
4 Composite 模式在具體實(shí)現(xiàn)中,可以讓父對(duì)象中的子對(duì)象反向追溯;如果父對(duì)象有頻繁的遍歷需求,可使用緩存技巧來改善效率。
適用性
以下情況下適用 Composite 模式:
1 .你想表示對(duì)象的部分 - 整體層次結(jié)構(gòu)
2 .你希望用戶忽略組合對(duì)象與單個(gè)對(duì)象的不同,用戶將統(tǒng)一地使用組合結(jié)構(gòu)中的所有對(duì)象。
總結(jié)
組合模式解耦了客戶程序與復(fù)雜元素內(nèi)部結(jié)構(gòu),從而使客戶程序可以向處理簡(jiǎn)單元素一樣來處理復(fù)雜元素。
參考資料
閻宏,《 Java 與模式》,電子工業(yè)出版社
James W. Cooper ,《 C# 設(shè)計(jì)模式》,電子工業(yè)出版社
Alan Shalloway James R. Trott ,《 Design Patterns Explained 》,中國電力出版社
MSDN WebCast C# 面向?qū)ο笤O(shè)計(jì)模式縱橫談 (9) Composite 組合模式 ( 結(jié)構(gòu)型模式 )

(第Ⅲ部分 結(jié)構(gòu)型模式篇) 第10章 組合模式(Composite Pattern)


更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主

微信掃碼或搜索:z360901061

微信掃一掃加我為好友

QQ號(hào)聯(lián)系: 360901061

您的支持是博主寫作最大的動(dòng)力,如果您喜歡我的文章,感覺我的文章對(duì)您有幫助,請(qǐng)用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點(diǎn)擊下面給點(diǎn)支持吧,站長(zhǎng)非常感激您!手機(jī)微信長(zhǎng)按不能支付解決辦法:請(qǐng)將微信支付二維碼保存到相冊(cè),切換到微信,然后點(diǎn)擊微信右上角掃一掃功能,選擇支付二維碼完成支付。

【本文對(duì)您有幫助就好】

您的支持是博主寫作最大的動(dòng)力,如果您喜歡我的文章,感覺我的文章對(duì)您有幫助,請(qǐng)用微信掃描上面二維碼支持博主2元、5元、10元、自定義金額等您想捐的金額吧,站長(zhǎng)會(huì)非常 感謝您的哦!!!

發(fā)表我的評(píng)論
最新評(píng)論 總共0條評(píng)論
主站蜘蛛池模板: 国产91亚洲精品 | 天天干影视 | 加勒比精品久久一区二区三区 | 成人免费久久精品国产片久久影院 | 日韩精品区 | 日韩精品中文字幕视频一区 | 国产精品视频播放 | 亚洲国产成a人v在线观看 | 国产成人av在线播放 | 国产一国产一区秋霞在线观看 | 亚洲一区二区色 | 国产午夜一区二区在线观看 | 91精品国产日韩91久久久久久360 | 精品国产青草久久久久福利 | 久久国产精品免费一区二区三区 | 国产精品国产三级在线专区 | 奇米影视88 | 麻豆精品一区二区 | 国产精品13页 | 久久香蕉国产线熟妇人妻 | 亚洲成人另类 | 特黄aaaaa日本大片免费看 | 国产午夜精品一区二区三区 | 国产亚洲精品久久久999无毒 | 91在线 | 成人国产精品齐天大性 | 日韩精品一区二区三区在线观看 | 日韩视频在线观看免费 | 久久久网 | 国产成人一区二区三区久久久 | 日本黄色一级视频 | 日本三级一区二区三区 | 久久黄网 | 日本不卡一区二区 | 精品亚洲永久免费精品 | 午夜午夜精品一区二区三区文 | 草草线在成人免费视频 | 欧美欲乱妇135 | 久久一区二区明星换脸 | 精品成人网| 性爱视频在线免费 |