久久国产成人av_抖音国产毛片_a片网站免费观看_A片无码播放手机在线观看,色五月在线观看,亚洲精品m在线观看,女人自慰的免费网址,悠悠在线观看精品视频,一级日本片免费的,亚洲精品久,国产精品成人久久久久久久

分享

.Net中的設(shè)計(jì)模式——Composite模式

 ljjzlm 2006-08-04

.Net中的設(shè)計(jì)模式——Composite模式

Filed under: .Net Framework, Design & Pattern — bruce zhang @ 1:17 pm

一,、模式概述

描述Composite模式的最佳方式莫過于樹形圖,。從抽象類或接口為根節(jié)點(diǎn)開始,然后生枝發(fā)芽,,以形成樹枝節(jié)點(diǎn)和葉結(jié)點(diǎn),。因此,,Composite模式通常用來描述部分與整體之間的關(guān)系,,而通過根節(jié)點(diǎn)對(duì)該結(jié)構(gòu)的抽象,使得客戶端可以將單元素節(jié)點(diǎn)與復(fù)合元素節(jié)點(diǎn)作為相同的對(duì)象來看待,。

由于Composite模式模糊了單元素和復(fù)合元素的區(qū)別,,就使得我們?yōu)檫@些元素提供相關(guān)的操作時(shí),可以有一個(gè)統(tǒng)一的接口,。例如,,我們要編寫一個(gè)字處理軟件,該軟件能夠處理文字,,對(duì)文章進(jìn)行排版,、預(yù)覽、打印等功能,。那么,,這個(gè)工具需要處理的對(duì)象,就應(yīng)該包括單個(gè)的文字,、以及由文字組成的段落,,乃至整篇文檔。這些對(duì)象從軟件處理的角度來看,,對(duì)外的接口應(yīng)該是一致的,,例如改變文字的字體,改變文字的位置使其居中或者右對(duì)齊,,也可以顯示對(duì)象的內(nèi)容,,或者打印。而從內(nèi)部實(shí)現(xiàn)來看,,我們對(duì)段落或者文檔進(jìn)行操作,,實(shí)質(zhì)上也是對(duì)文字進(jìn)行操作。從結(jié)構(gòu)來看,,段落包含了文字,,文檔又包含了段落,是一個(gè)典型的樹形結(jié)構(gòu),。而其根節(jié)點(diǎn)正是我們可以抽象出來暴露在外的統(tǒng)一接口,,例如接口IElement:

composite1.GIF

既然文字、段落、文檔都具有這些操作,,因此它們都可以實(shí)現(xiàn)IElement接口:

從上圖可以看到,,對(duì)象Word、Paragraph,、Document均實(shí)現(xiàn)了IElement接口,,但Paragraph和Document與Word對(duì)象不同的是,這兩者處除了實(shí)現(xiàn)了IElement接口,,它們還與IElement接口對(duì)象之間具有聚合的關(guān)系,,且是一對(duì)多。也就是說Paragraph與Document對(duì)象內(nèi)可以包含0個(gè)到多個(gè)IElement對(duì)象,,這也是與前面對(duì)字處理軟件分析獲得的結(jié)果是一致的,。

從整個(gè)結(jié)構(gòu)來看,完全符合樹形結(jié)構(gòu)的各個(gè)要素,,接口IElement是根節(jié)點(diǎn),,而Paragraph和Document類為枝節(jié)點(diǎn),Word對(duì)象為葉節(jié)點(diǎn),。既然作為枝節(jié)點(diǎn),,它就具有帶葉節(jié)點(diǎn)的能力,從上圖的聚合關(guān)系中我們體現(xiàn)出了這一點(diǎn),。也就是說,,Paragraph和Document類除了具有排版、打印方面的職責(zé)外,,還能夠添加,、刪除葉節(jié)點(diǎn)的操作。那么這些操作應(yīng)該放在哪里呢,?

管理對(duì)子節(jié)點(diǎn)的管理,,Composite模式提供了兩種方式:一個(gè)是透明方式,也就是說在根節(jié)點(diǎn)中聲明所有用來管理子元素的方法,,包括Add(),、Remove()等方法。這樣一來,,實(shí)現(xiàn)根節(jié)點(diǎn)接口的子節(jié)點(diǎn)同時(shí)也具備了管理子元素的能力,。這種實(shí)現(xiàn)策略,最大的好處就是完全消除了葉節(jié)點(diǎn)和枝節(jié)點(diǎn)對(duì)象在抽象層次的區(qū)別,,它們具備完全一致的接口,。而缺點(diǎn)則是不夠安全。由于葉節(jié)點(diǎn)本身不具備管理子元素的能力,,因此提供的Add(),、Remove()方法在實(shí)現(xiàn)層次是無意義的,。但客戶端調(diào)用時(shí),卻看不到這一點(diǎn),,從而導(dǎo)致在運(yùn)行期間有出錯(cuò)的可能,。

另一種策略則是安全方式。與透明方式剛好相反,,它只在枝節(jié)點(diǎn)對(duì)象里聲明管理子元素的方法,,由于葉節(jié)點(diǎn)不具備這些方法,當(dāng)客戶端在操作葉節(jié)點(diǎn)時(shí),,就不會(huì)出現(xiàn)前一種方式的安全錯(cuò)誤,。然而,這種實(shí)現(xiàn)方式,,卻導(dǎo)致了葉節(jié)點(diǎn)和枝節(jié)點(diǎn)接口的不完全一致,,這給客戶端操作時(shí)帶來了不便。

這兩種方式各有優(yōu)缺點(diǎn),,我們?cè)趯?shí)現(xiàn)時(shí),應(yīng)根據(jù)具體的情況,,作出更加合理的抉擇,。在字處理軟件一例中,我選擇了安全方式來實(shí)現(xiàn),,因?yàn)閷?duì)于客戶端而言,,在調(diào)用IElement接口時(shí),通常是將其視為可被排版,、打印等操作的對(duì)象,。至于為Paragraph和Document對(duì)象添加、刪除子對(duì)象,,往往是一種初始化的行為,,完全可以放到一個(gè)單獨(dú)的模塊中。根據(jù)單一職責(zé)原則(SRP),,我們沒有必要讓IElement接口負(fù)累太重,。所以,我們需要對(duì)上圖作稍許的修改,,在Paragraph和Document對(duì)象中增加Add()和Remove()方法:

以下是IElement對(duì)象結(jié)構(gòu)的實(shí)現(xiàn)代碼:
public interface IElement
{
      void ChangeFont(Font font);
      void Show();
      //其他方法略;
}
public class Word
{
 public void ChangeFont(Font font)
 {
      this.font = font;
 }
 public void Show()
 {
      Console.WriteLine(this.ToString());
 }
 //其他方法略;
}
public class Paragraph
{
 private ArrayList elements = new ArrayList();
 public void Add(IElement element)
 {
      elements.Add(element);
 }
 public void Remove(IElement element)
 {
      elements.Remove(element);
 }
 public void ChangeFont(Font font)
 {
      foreach (IElement element in elements)
      {
          element.ChangeFont(font);
  }
 }
 public void Show()
 {
      foreach (IElement element in elements)
      {
          element.Show(font);
  }
 }
 //其他方法略;
}
//Document類略,;

實(shí)際上,我們?cè)跒槿~節(jié)點(diǎn)實(shí)現(xiàn)Add(),,Remove()方法時(shí),,還需要考慮一些異常情況。例如在Paragraph類中,,添加的子元素就不能是Document對(duì)象和Paragraph對(duì)象,。所以在添加IElement對(duì)象時(shí),,還需要做一些條件判斷,以確定添加行為是否正確,,如果錯(cuò)誤,,應(yīng)拋出異常。

采用Composite模式,,我們將Word,、Paragraph、Document抽象為IElement接口,。雖然各自內(nèi)部的實(shí)現(xiàn)并不相同,,枝節(jié)點(diǎn)和葉節(jié)點(diǎn)的實(shí)質(zhì)也不一樣,但對(duì)于調(diào)用者而言,,是沒有區(qū)別的,。例如在類WordProcessor中,包含一個(gè)GetSelectedElement()靜態(tài)方法,,它能夠獲得當(dāng)前選擇的對(duì)象:
public class WordProcessor
{
 public static IElement GetSelectedElement(){……}
}

對(duì)于字處理軟件的UI來說,,如果要改變選中對(duì)象的字體,則可以在命令按鈕cmdChangeFont的Click事件中寫下如下代碼:
public void cmdChangeFont_Click(object sender, EventArgs e)
{
    WordProcessor.GetSelectedElement().ChangeFont(currentFont);
}

不管當(dāng)前選中的對(duì)象是文字,、段落還是整篇文檔,,對(duì)于UI而言,操作都是完全一致的,,根本不需要去判斷對(duì)象的類別,。因此,如果在Business Layer的類庫設(shè)計(jì)時(shí),,采用Composite模式,,將極大地簡(jiǎn)化UI表示層的開發(fā)工作。此外,,應(yīng)用該模式也較好的支持項(xiàng)目的可擴(kuò)展性,。例如,我們?yōu)镮Element接口增加了Sentence類,,對(duì)于前面的例子而言,,只需要修改GetSelectedElement()方法,而cmdChangeFont命令按鈕的Click事件以及Business Layer類庫原有的設(shè)計(jì),,都不需要做任何改變,。這也符合OO的開放-封閉原則(OCP),即對(duì)于擴(kuò)展是開放的(Open for extension),,對(duì)于更改則是封閉的(Closed for modification),。

二、.Net Framework中的Composite模式

在.Net中,,最能體現(xiàn)Composite模式的莫過于Windows或Web的控件,。在這些控件中,,有的包含子控件,有的則不包含且不能包含子控件,,這正好符合葉節(jié)點(diǎn)和枝節(jié)點(diǎn)的含義,。所有Web控件的基類為System.Web.UI.Contril類(如果是Windows控件,則基類為System.Windows.Forms.Control類),。其子類包含有HtmlControl,、HtmlContainerControl等。按照Composite模式的結(jié)構(gòu),,枝節(jié)點(diǎn)和葉節(jié)點(diǎn)屬于根節(jié)點(diǎn)的不同分支,,同時(shí)枝節(jié)點(diǎn)與根節(jié)點(diǎn)之間應(yīng)具備一個(gè)聚合關(guān)系,可以通過Add(),、Remove()方法添加和移除其子節(jié)點(diǎn),。設(shè)定HtmlControl為葉節(jié)點(diǎn),而HtmlContaiinerControl為枝節(jié)點(diǎn),,那么采用透明方式的設(shè)計(jì)方法,,在.Net中控件類的結(jié)構(gòu),就應(yīng)該如下圖所示:

雖然根據(jù)透明方式的Composite模式,,HtmlControl類與其父類Control之間也應(yīng)具備一個(gè)聚合關(guān)系,,但實(shí)質(zhì)上該類并不具備管理子控件的職責(zé),因此我在類圖中忽略了這個(gè)關(guān)系,。此時(shí),HtmlControl類中的Add(),、Remove()方法,,應(yīng)該為空,或者拋出一個(gè)客戶端能夠捕獲的異常,。

然而,,從具體實(shí)現(xiàn)來考慮,由于HtmlControl類和HtmlContainerControl類在實(shí)現(xiàn)細(xì)節(jié)層次,,區(qū)別僅在于前者不支持子控件,,但從控件本身的功能來看,很多行為是相同或者相近的,。例如HtmlControl類的Render()方法,,調(diào)用了方法RenderBeginTag()方法:
protected override void Render(HtmlTextWriter writer)
{
      this.RenderBeginTag(writer);
}
protected virtual void RenderBeginTag(HtmlTextWriter writer)
{
      writer.WriteBeginTag(this.TagName);
      this.RenderAttributes(writer);
      writer.Write(’>‘);
}

而HtmlContainerControl類也具有Render()方法,在這個(gè)方法中也調(diào)用了RenderBeginTag()方法,,且RenderBeginTag方法的實(shí)現(xiàn)和前者完全一致:
protected override void Render(HtmlTextWriter writer)
{
      this.RenderBeginTag(writer);
      this.RenderChildren(writer);
      this.RenderEndTag(writer);
}

按照上面的結(jié)構(gòu),,由于HtmlControl和HtmlContainerControl之間并無繼承關(guān)系,這就要求兩個(gè)類中,,都要重復(fù)實(shí)現(xiàn)RenderBeginTag()方法,,從而導(dǎo)致產(chǎn)生重復(fù)代碼,。根據(jù)OO的特點(diǎn),解決的辦法,,就是讓HtmlContainerControl繼承自HtmlControl類(因?yàn)镠tmlContainerControl的接口比HtmlControl寬,,所以只能令HtmlContainerControl作為子類),并讓RenderBeginTag()方法成為HtmlControl類的protected方法,,子類HtmlContainerControl可以直接調(diào)用這個(gè)方法,。然而與之矛盾的是,HtmlContainerControl卻是一個(gè)可以包含子控件的枝節(jié)點(diǎn),,而HtmlControl則是不能包含子控件的葉節(jié)點(diǎn),,那么這樣的繼承關(guān)系還成立嗎?

HtmlControl類對(duì)Add()方法和Remove()方法的重寫后,,這兩個(gè)方法內(nèi)容為空,。由于HtmlContainerControl類繼承HtmlControl類,但我們又要求它的Add()和Remove()方法和Control類保持一致,,而父類HtmlControl已經(jīng)重寫這兩個(gè)方法,,此時(shí)是無法直接繼承來自父類的方法的。以上是采用透明方式的設(shè)計(jì),。

如果采用安全方式,,仍然有問題。雖然在HtmlControl類中不再有Add()和Remove()方法,,但由于Control類和HtmlContainerControl類都允許添加子控件,,它們包含的Add()、Remove()方法,,只能分別實(shí)現(xiàn),。這樣的設(shè)計(jì)必然會(huì)導(dǎo)致重復(fù)代碼。這也是與我們的期望不符的,。

那么在.Net中,,Control類究竟是怎樣實(shí)現(xiàn)的呢?下面,,我將根據(jù).Net實(shí)現(xiàn)Control控件的源代碼,,來分析Control控件的真實(shí)結(jié)構(gòu),以及其具體的實(shí)現(xiàn)細(xì)節(jié),。

三,、深入分析.Net中的Composite模式

首先,我們來剖析Web控件的基類Control類的內(nèi)部實(shí)現(xiàn):

public class Control : IComponent, IDisposable, IParserAccessor, IDataBindingsAccessor
{
       // Events;略  
       // Methods
 public Control()
 {
             if (this is INamingContainer)
             {
                    this.flags[0×80] = true;
             }
 }
 public virtual bool HasControls()
 {
              if (this._controls != null)
              {
                    return (this._controls.Count > 0);
              }
              return false;
 }
 public virtual void DataBind()
        {
              this.OnDataBinding(EventArgs.Empty);   
              if (this._controls != null)           
       {                
              string text1 = this._controls.SetCollectionReadOnly(”Parent_collections_readonly”);
                        int num1 = this._controls.Count;
                 for (int num2 = 0; num2 < num1; num2++)                 
   {
                         this._controls[num2].DataBind();
                   }
                   this._controls.SetCollectionReadOnly(text1);
              }
 }
        protected virtual void Render(HtmlTextWriter writer)
 {
              this.RenderChildren(writer);
 }
 protected virtual ControlCollection CreateControlCollection()
 {
              return new ControlCollection(this);
 }
       // Properties
 public virtual ControlCollection Controls
 {
             get
             {
                   if (this._controls == null)
                   {
                         this._controls = this.CreateControlCollection();
                   }
                   return this._controls;
             }
 }
        // Fields
        private ControlCollection _controls;
}

Control基類中的屬性和方法很多,,為清晰起見,,我只保留了幾個(gè)與模式有關(guān)的關(guān)鍵方法與屬性。在上述的源代碼中,,我們需要注意幾點(diǎn):

1,、Control類不是抽象類,,而是具體類。這是因?yàn)樵谠O(shè)計(jì)時(shí),,我們可能會(huì)創(chuàng)建Control類型的實(shí)例,。根據(jù)這一點(diǎn)來看,這并不符合OOP的要求,。一般而言,,作為抽象出來的基類,必須定義為接口或抽象類,。不過在實(shí)際的設(shè)計(jì)中,,也不應(yīng)拘泥于這些條條框框,而應(yīng)審時(shí)度勢(shì),,根據(jù)實(shí)際的情況來抉擇最佳的設(shè)計(jì)方案,。
2、公共屬性Controls為ControlCollection類型,,且該屬性為virtual屬性,。也就是說,這個(gè)屬性可以被它的子類override,。同時(shí),,該屬性為只讀屬性,在其get訪問器中,,調(diào)用了方法CreateControlCollection(),;這個(gè)方法為protected虛方法,默認(rèn)的實(shí)現(xiàn)是返回一個(gè)ControlCollection實(shí)例,。
3,、方法HasControls(),功能為判斷Control對(duì)象是否有子控件,。它判斷的依據(jù)是根據(jù)私有字段_controls(即公共屬性Controls)的Count值。但是需要注意的是,,通過HasControls()方法的返回值,,并不能決定對(duì)象本身屬于葉節(jié)點(diǎn),還是枝節(jié)點(diǎn),。因?yàn)榧词故侵?jié)點(diǎn)其內(nèi)部仍然可以不包含任何子對(duì)象,。
4、 方法DataBind()的實(shí)現(xiàn)中,,首先調(diào)用了自身的OnDataBinding()方法,,然后又遍歷了Controls中的所有控件,并調(diào)用其DataBind()方法,。該方法屬于控件的共有行為,,從這里可以看出不管是作為葉節(jié)點(diǎn)的控件,,還是作為枝節(jié)點(diǎn)的控件,它們都實(shí)現(xiàn)統(tǒng)一的接口,。對(duì)于客戶端調(diào)用而言,,枝節(jié)點(diǎn)和葉節(jié)點(diǎn)是沒有區(qū)別的。
5,、 Control類的完整源代碼中,,并不存在Add()、Remove()等類似的方法,,以提供添加和移除子控件的功能,。事實(shí)上,繼承Control類的所有子類均不存在Add(),、Remove()等方法,。

顯然,在Control類的定義和實(shí)現(xiàn)中,,值得我們重視的是公共屬性Controls的類型ControlCollection,。顧名思義,該類必然是一個(gè)集合類型,。是否有關(guān)子控件的操作,,都是在ControlCollection類型中實(shí)現(xiàn)呢?我們來分析一下ControlCollection的代碼:
public class ControlCollection : ICollection, IEnumerable
{
       // Methods
 public ControlCollection(Control owner)
 {
               this._readOnlyErrorMsg = null;
               if (owner == null)
               {
                       throw new ArgumentNullException("owner");
               }
               this._owner = owner;
        }
 public virtual void Add(Control child)
        {
               if (child == null)
               {
                throw new ArgumentNullException("child");
               }
               if (this._readOnlyErrorMsg != null)
                   {
                throw new HttpException(HttpRuntime.FormatResourceString(this._readOnlyErrorMsg));
               }
               if (this._controls == null)
               {
                   this._controls = new Control[5];
               }
               else if (this._size >= this._controls.Length)
               {
                   Control[] controlArray1 = new Control[this._controls.Length * 4];
                   Array.Copy(this._controls, controlArray1, this._controls.Length);
                   this._controls = controlArray1;
               }
               int num1 = this._size;
               this._controls[num1] = child;
               this._size++;
               this._version++;
               this._owner.AddedControl(child, num1);
        }
        public virtual void Remove(Control value)
 {
               int num1 = this.IndexOf(value);
               if (num1 >= 0)
               {
                this.RemoveAt(num1);
               }
        }
        // Indexer
 public virtual Control this[int index]
 {
               get
               {
                    if ((index < 0) || (index >= this._size))
                    {
                         throw new ArgumentOutOfRangeException(”index”);
                    }
                    return this._controls[index];
               }
 }
 // Properties    
 public int Count
 {
        get
               {
                    return this._size;
               }
        }
 protected Control Owner
 {
               get
               {
                    return this._owner;
               }
 }
        protected Control Owner { get; }   
        // Fields
        private Control[] _controls;
        private const int _defaultCapacity = 5;
        private const int _growthFactor = 4;
 private Control _owner;    
}

一目了然,,正是ControlCollection的Add(),、Remove()方法完成了對(duì)子控件的添加和刪除。例如:
Control parent = new Control();
Control child = new Child();
//添加子控件child;
parent.Controls.Add(child);
//移除子控件child;
parent.Controls.Remove(child);

為什么要專門提供ControlCollection類型來管理控件的子控件呢,?首先,,作為類庫使用者,自然希望各種類型的控件具有統(tǒng)一的接口,,尤其是自定義控件的時(shí)候,,不希望自己重復(fù)定義管理子控件的操作;那么采用透明方式自然是最佳方案,。然而,,在使用控件的時(shí)候,安全也是需要重點(diǎn)考慮的,,如果不考慮子控件管理的合法性,,一旦使用錯(cuò)誤,會(huì)導(dǎo)致整個(gè)應(yīng)用程序出現(xiàn)致命錯(cuò)誤,。從這樣的角度考慮,,似乎又應(yīng)采用安全方式。這里就存在一個(gè)抉擇。故而,,.Net在實(shí)現(xiàn)Control類庫時(shí),,利用了職責(zé)分離的原則,將控件對(duì)象管理子控件的屬性與行為和控件本身分離,,并交由單獨(dú)的ControlCollection類負(fù)責(zé),。同時(shí)采用聚合而非繼承的方式,以一個(gè)公共屬性Controls,,存在于Control類中,。這種方式,集保留了透明方式和安全方式的優(yōu)勢(shì),,又摒棄了這兩種方式固有的缺陷,,因此我名其為“復(fù)合方式”。

“復(fù)合方式”的設(shè)計(jì),,其對(duì)安全的保障,,不僅僅是去除了Control類關(guān)于子控件管理的統(tǒng)一接口,同時(shí)還通過異常管理的方式,,在ControlCollection類的子類中實(shí)現(xiàn):
public class EmptyControlCollection : ControlCollection
{
        // Methods
 public EmptyControlCollection(Control owner) : base(owner)
 {}
 public override void Add(Control child)
 {
            this.ThrowNotSupportedException();
 }                         
        private void ThrowNotSupportedException()
        {
            throw new HttpException(HttpRuntime.FormatResourceString(”Control_does_not_allow_children”, base.Owner.GetType().ToString()));
        }
}

EmptyControlCollection繼承了ControlCollection類,,并重寫了Add()等添加子控件的方法,使其拋出一個(gè)異常,。注意,,它并沒有重寫父類的Remove()方法,這是因?yàn)镃ontrolCollection類在實(shí)現(xiàn)Remove()方法時(shí),,對(duì)集合內(nèi)的數(shù)據(jù)進(jìn)行了非空判斷,。而在EmptyControlCollection類中,是不可能添加子控件的,,直接調(diào)用父類的Remove()方法,,是不會(huì)出現(xiàn)錯(cuò)誤的。

既然管理子控件的職責(zé)由ControlCollection類型負(fù)責(zé),,且Control類中的公共屬性Controls即為ControlCollection類型,。所以,對(duì)于控件而言,,如果是樹形結(jié)構(gòu)中的葉節(jié)點(diǎn),,它不能包含子控件,它的Controls屬性就應(yīng)為EmptyControlCollection類型,,假如用戶調(diào)用了Controls的Add()方法,就會(huì)拋出異常,。如果控件是樹形結(jié)構(gòu)中的枝節(jié)點(diǎn),,它支持子控件,那么Controls屬性就是ControlCollection類型。究竟是枝節(jié)點(diǎn)還是葉節(jié)點(diǎn),,決定權(quán)在于公共屬性Controls:
public virtual ControlCollection Controls
{
      get
      {
             if (this._controls == null)
             {
                   this._controls = this.CreateControlCollection();
             }
             return this._controls;
      }
}

在屬性的get訪問器中,,調(diào)用了protected方法CreateControlCollection(),它創(chuàng)建并返回了一個(gè)ControlCollection實(shí)例:
protected virtual ControlCollection CreateControlCollection()
{
     return new ControlCollection(this);
}

很明顯,,在Control基類實(shí)現(xiàn)Controls屬性時(shí),,采用了Template Method模式,它推遲了ControlCollection的創(chuàng)建,將決定權(quán)交給了CreateControlCollection()方法,。

如果我們需要定義一個(gè)控件,,要求它不能管理子控件,就重寫CreateControlCollection()方法,,返回EmptyControlCollection對(duì)象:

protected override ControlCollection CreateControlCollection()
{
     return new EmptyControlCollection(this);
}
 
現(xiàn)在再回過頭來看HtmlControl和HtmlContainerControl類,。根據(jù)前面的分析,我們要求HtmlContainerControl繼承HtmlControl類,,同時(shí),,HtmlContainerControl應(yīng)為枝節(jié)點(diǎn),能夠管理子控件,;HtmlControl則為葉節(jié)點(diǎn),,不支持子控件。通過引入ControlCollection類和其子類EmptyControlCollection,,以及Template Method模式后,,這些類之間的關(guān)系與結(jié)構(gòu)如下所示:

HtmlContainerControl繼承了HtmlControl類,這兩個(gè)類都重寫了自己父類的protected方法CreateControlCollection(),。HtmlControl類,,該方法返回EmptyControlCollection對(duì)象,使其成為了不包含子控件的葉節(jié)點(diǎn),;HtmlContainerControl類中,,該方法則返回ControlCollection對(duì)象,從而被賦予了管理子控件的能力,,成為了枝節(jié)點(diǎn):
public abstract class HtmlControl : Control, IAttributeAccessor
{
        // Methods
 protected override ControlCollection CreateControlCollection()
 {
            return new EmptyControlCollection(this);
 }
}
public abstract class HtmlContainerControl : HtmlControl
{
       // Methods
 protected override ControlCollection CreateControlCollection()
 {
            return new ControlCollection(this);
 }
}

HtmlControl和HtmlContainerControl類均為抽象類,。要定義它們的子類,如果不重寫其父類的CreateControlCollection()方法,,那么它們的Controls屬性,,就與父類完全一致。例如HtmlImage控件繼承自HtmlControl類,,該控件不能添加子控件,;而HtmlForm控件則繼承自HtmlContainerControl類,顯然,,HtmlForm控件是支持添加子控件的操作的,。

.Net的控件設(shè)計(jì)采用Composite模式的“復(fù)合方式”,較好地將控件的透明性與安全性結(jié)合起來,它的特點(diǎn)是:

1,、在統(tǒng)一接口中消除了Add(),、Remove()等子控件的管理方法,而由ControlCollection類實(shí)現(xiàn),,同時(shí)通過EmptyControlCollection類保障了控件進(jìn)一步的安全,;
2、控件能否管理子控件,,不由繼承的層次決定,;而是通過重寫CreateControlCollection()方法,由Controls屬性的真正類型來決定,。

如此一來,,要定義自己的控件就更加容易。我們可以任意地?cái)U(kuò)展自己的控件類,。不管繼承自Control,,還是HtmlControl或HtmlContainerControl,都可以輕松地定義出具有枝節(jié)點(diǎn)或葉節(jié)點(diǎn)屬性的新控件,。如果有新的需求要求改變管理子控件的方式,,我們還可以定義繼承自ControlCollection的類,并在控件類的方法CreateControlCollection()中創(chuàng)建并返回它的實(shí)例,。

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn),。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式,、誘導(dǎo)購買等信息,謹(jǐn)防詐騙,。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多