程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> .NET實例教程 >> DotNet源代碼中的模式Builder生成器模式

DotNet源代碼中的模式Builder生成器模式

編輯:.NET實例教程

將一個復雜對象的構件與它的表示分離,使得同樣的構建過程可以創建不同的表述。

DotNet源代碼中的模式Builder生成器模式 

  建造者(Builder)角色:給出一個抽象接口,以規范產品對象的各個組成成分的建造。一般而言,此接口獨立於應用程序的商業邏輯。模式中直接創建產品對象的是具體建造者(ConcreteBuilder)角色。具體建造者類必須實現這個接口所要求的方法:一個是建造方法,另一個是結果返還方法。

  具體建造者(Concrete Builder)角色:擔任這個角色的是於應用程序緊密相關的類,它們在應用程序調用下創建產品實例。這個角色主要完成的任務包括:實現Builder角色提供的接口,一步一步完成創建產品實例的過程;在建造過程完成後,提供產品的實例。

  指導者(Director)角色:擔任這個角色的類調用具體建造者角色以創建產品對象。導演者並沒有產品類的具體知識,真正擁有產品類的具體知識的是具體建造者對象。

  產品(Product)角色:產品便是建造中的復雜對象。

  以以.Net Framework 2.0 System.Text. StringBuilder為例

  System.Text. StringBuilder

Code
public sealed class StringBuilder : ISerializable
{
    //
    internal IntPtr m_currentThread = Thread.InternalGetCurrentThread();
    internal int m_MaxCapacity = 0; 
    internal volatile String m_StringValue = null;
    //
    public StringBuilder() : this(DefaultCapacity)
    {

    }
    //
    public StringBuilder Append(String value)
    {
        //If the value being added is null, eat the null
        //and return. 
        if (value == null)
        {
            return this;
        }

        IntPtr tid;
        // hand inlining of GetThreadSafeString 
        String currentString = m_StringValue;
        tid = Thread.InternalGetCurrentThread();
        if (m_currentThread != tid)
            currentString = String.GetStringForStringBuilder(currentString, currentString.Capacity);

        int currentLength = currentString.Length;

        int requiredLength = currentLength + value.Length;

        if (NeedsAllocation(currentString, requiredLength))
        {
            String newString = GetNewString(currentString, requiredLength);
            newString.AppendInPlace(value, currentLength);
            ReplaceString(tid, newString);
        }
        else
        {
            currentString.AppendInPlace(value, currentLength);
            ReplaceString(tid, currentString);
        }

        return this;
    }
    //
    public StringBuilder Append(int value)
    {
        return Append(value.ToString(CultureInfo.CurrentCulture));
    }
    //
    public override String ToString()
    {
        //
        // We assume that their read of m_currentThread will always occur after read of m_StringValue.
        // If these reads get re-ordered then it is possible to get a currentString owned by some other 
        // (mutating) thread and yet think, according to currentThread, that such was not the case.
        // This is acheived by marking m_StringValue as volatile. 
        // 
        String currentString = m_StringValue;
        IntPtr currentThread = m_currentThread;  //
        // Note calling ToString the second time or from a different thread will cause allocation of a new string.
        // If we do not make a copy if currentThread is IntPtr.Zero, we will have following race:
        //
        // (1) Thread T1 completes a mutation of the string and will become the owner. 
        // T1 then starts another mutation Operation and 
        // A thread interleaving happens at this point.
        // (2) Thread T2 starts a ToString Operation.  T2 reads m_StringValue into its local currentString variable. 
        // A thread interleaving happens at this point.
        // (3) Thread T3 finshes a mutation of the string in the StringBuilder , performing the ReplaceString call.
        // Thread T3 then starts a ToString Operation.  Assuming the string is not wasting excessive space,
        // T3 will proceeds to call ClearPostNullChar, registers NOBODY as the owner, and returns the string. 
        // A thread interleaving happens at this point.
        // (4) Thread T2 resumes execution.  T2 reads m_currentThread and sees that NOBODY is the registered owner 
        //  Assuming its currentString is not wasting excessive space, T2 will return the same string that thread T1 is 
        //  in the middle of mutating.
        // 
        if (currentThread != Thread.InternalGetCurrentThread())
        {
            return String.InternalCopy(currentString);
        }

        if ((2 * currentString.Length) < currentString.ArrayLength)
        {
            return String.InternalCopy(currentString);
        }

        currentString.ClearPostNullChar();
        m_currentThread = IntPtr.Zero;
        return currentString;
    }
}

 

System.String

Code
public sealed class String : IComparable, ICloneable, IConvertible, IEnumerable
{
    //
    // Creates a new string with the characters copIEd in from ptr. If 
    // ptr is null, a string initialized to ";<;No Object>;"; (i.e., 
    // String.NullString) is created.
    // 
    [CLSCompliant(false), MethodImplAttribute(MethodImplOptions.InternalCall)]
    unsafe public extern String(char* value);
    [CLSCompliant(false), MethodImplAttribute(MethodImplOptions.InternalCall)]
    unsafe public extern String(char* value, int startIndex, int length);

    [CLSCompliant(false), MethodImplAttribute(MethodImplOptions.InternalCall)]
    unsafe public extern String(sbyte* value);
    [CLSCompliant(false), MethodImplAttribute(MethodImplOptions.InternalCall)]
    unsafe public extern String(sbyte* value, int startIndex, int length);

    [CLSCompliant(false), MethodImplAttribute(MethodImplOptions.InternalCall)]
    unsafe public extern String(sbyte* value, int startIndex, int length, Encoding enc);
    //
    // Creates a new string from the characters in a subarray.  The new string
will
    // be created from the characters in value between startIndex and
    // startIndex + length - 1. 
    //
    [MethodImplAttribute(MethodImplOptions.InternalCall)]
    public extern String(char[] value, int startIndex, int length);

    // Creates a new string from the characters in a subarray.  The new string will be 
    // created from the characters in value.
    //

    [MethodImplAttribute(MethodImplOptions.InternalCall)]
    public extern String(char[] value);
    //

    internal unsafe void AppendInPlace(String value, int currentLength)
    {
        int count = value.Length;
        int newLength = currentLength + count;

        //

        fixed (char* dest = &this.m_firstChar)
        {
            fixed (char* src = &value.m_firstChar)
            {
                wstrcpy(dest + currentLength, src, count);
            }
            dest[newLength] = '';
        }
        this.m_stringLength = newLength;
    }

    //

}

調用代碼

Code
public class ClIEnt
{
    public static void Main()
    {
        StringBuilder sb = new StringBuilder();
        sb.Append("Hello");
        sb.Append(" World");
        sb.Append("!");

        String s = sb.ToString();
     
        Console.Write(s);     
        Console.ReadLine();
    }
}

  由於String類型代表的是一個不可變的字符串,所以BCL提供了另一個名為System.Text.StringBuilder的類型,它允許我們有效的對字符串的字符執行動態操作,以創建一個String。

  從邏輯上說,StringBuilder對象中包含一個字段,它引用由Char結構構成的一個數組。StringBuilder的成員允許我們操作這個字符,有效的縮減字符串的大小或者更改字符串中的字符。如果字符串變大,超過已經分配的字符的大小,StringBuilder就會自動的分配一個全新的、更大的數組,並開始使用新的數組,前一個數組會被垃圾回收器回收。用StringBuilder對象構建好字符串之後,為了將StringBuilder的字符“轉換”成一個String,只需調用StringBuilder的ToString方法,在內部,該方法只是返回對StringBuilder內部維護的字符串的字段的一個引用,執行效率非常快,因為它不需要進行字符數組復制。

  C#中volatile 關鍵字指示一個字段可以由多個同時執行的線程修改。聲明為 volatile 的字段不受編譯器優化(假定由單個線程訪問)的限制。這樣可以確保該字段在任何時間呈現的都是最新的值。可變關鍵字僅可應用於類或結構字段。不能將局部變量聲明為 volatile。


  StringBuilder既是具體建造者(Builder)又是指導者(Director),最終生成一個復雜的String對象作為產品(Product)。在具體建造者只有一個的情況下,如果抽象建造者角色已經被省略掉,那麼還可以省略掉指導者角色。讓Builder角色自己扮演指導者與建造者雙重角色。

  以下情況應當使用建造者模式:

  1.需要生成的產品對象有復雜的內部結構。

  2.需要生成的產品對象的屬性相互依賴,建造者模式可以強迫生成順序。

  3.在對象創建過程中會使用到系統中的一些其它對象,這些對象在產品對

  象的創建過程中不易得到。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved