天天看點

設計模式系列-建立者模式

        上篇我們主要講述了抽象工廠模式和工廠模式。并且分析了該模式的應用場景和一些優缺點,并且給出了一些實作的思路和方案,我們現在來回顧一下:         抽象工廠模式:一個工廠負責所有類型對象的建立,支援無縫的新增新的類型對象的建立。這種情況是通過配置檔案來實作的,通過字典映射的方式來實作,不過可能效率上有點低下,可以通過優化的方式 來做,上篇中我們也給出了委托的工廠實作形式,相比之前的簡單工廠模式和工廠模式有了更好的靈活性,并且對具有依賴關系或者組合關系的對象的建立尤為适合。         上篇中,有不少的朋友提出了一些意見和建議,首先很感謝大夥的支援和鼓勵,有朋友提出來,我畫的圖不夠專業,專業人士應該用UML模組化圖來搞,我怎麼說呢?我也同意這樣的說法,但是我發現我通過 另外的直覺的圖形,大家一看就能更明白,結合代碼,當然好的UML圖,已經能表述清楚設計的思路和大體實作了,不過說實話,我看着就有點類,特别是UML圖複雜的時候。是以我還是暫時先用這種一般的圖 形來表述我了解的設計模式的思想,看看大夥是什麼看法和意見,如果說都說說UML圖的話,那麼後面的相關模式,我會主要以UML專業圖來繪制。         我這裡總結下我們以後項目中的可能會用到設計模式 之處或者系統架構的時候,一般情況下有這樣的幾類方案,我們可以在考慮系統的低耦合性的時候的設計: 注在文章中。
        本文主要是針對建立型模式中的建立者模式進行講述,建立者模式是建立型模式中最負責的一個設計模式了,建立者負責建構一個對象的各個部分,并且完成組裝的過程,我們可以這麼了解建立 者模式,建立者模式類似與一個步驟基本固定,但是每個步驟中的具體形式卻又可以變化的這類對象的建立。也許這樣說還是太抽象了,我們這麼來了解吧,我感覺讓人最容易了解的形式還是圖形化 的形式,不但接受起來容易,并且讓人映象深刻,不知道大家是不是和我有同感呢?下面我們給出一個簡單的例子,通過圖形化的流程來說明吧:我們這裡以我們大夥平時最常見的做飯為例吧:
       a、上篇回顧。        b、摘要。        c、本文大綱。        d、建立者模式的特點及使用場景。        e、建立者模式的實作方案。        f、建立者模式使用總結。        g、系列進度。        h、下篇預告。
      建立者模式主要是用于建立複雜的一些對象,這些對象的建立步驟基本固定,但是可能具體的對象的組成部分卻又可以自由的變化,現實中的例子很多,但是可能大夥都比較容易了解的就是,我 們的自己花錢配置的桌上型電腦或者筆記本,可以 這樣了解,這些硬體裝置的各個零件,不管是CPU是Intel的還是AMD的,顯示卡是華碩的還是小影霸的,不管硬碟是西部資料的還是希捷的,其實想表述 的意思就是對象的具體的組成部分可以是變化的,但是可能我們發現對象的這些組成部分的組織起來的過程是相對固定的,那麼我們就可以用建立者模式來做,并且我們引入一個引導者(Director)來 引導這個對象的組裝過程。可以簡單用圖形化的過程來描述如下: 生産的帽子,上衣等都會發生變化,但是服裝的組裝過程基本上變化不大,都是需要帽子,上衣,褲子的,這時候我們可以通過引導着負責組裝這樣的過程,然後我們在具體的每個部分可以是抽象接 口,根據不同的實作建立不同的帽子來完成變化。

我們先給出經典建立者模式的一個實作形式,然後針對這個經典模式後面提出幾個改進方案,我們這裡以上面講述的服裝的過程作為例子來說明下建立者模式的原理和思想,希望大家也能靈活的運用到實際的項目中去。達到學以緻用的目的。

我們來看看具體的代碼實作:
<a href="http://blog.51cto.com/2435232/440214#">?</a> 1 2 3 4 5 6 7 8 9 <code>/// &lt;summary&gt;</code> <code>/// 建立對象組織的所有構造步驟接口</code> <code>/// &lt;/summary&gt;</code> <code>public</code> <code>interface</code> <code>IBuider</code> <code>{</code> <code>    </code><code>void</code> <code>BuilderPart1();</code> <code>    </code><code>void</code> <code>BuilderPart2();</code> <code>    </code><code>void</code> <code>BuilderPart3();</code> <code>}</code>
定義一個服裝對象:
<code>/// 服裝對象</code> <code>public</code> <code>class</code> <code>Dress</code> <code>    </code><code>/// &lt;summary&gt;</code> <code>    </code><code>/// 建構帽子</code> <code>    </code><code>/// &lt;/summary&gt;</code> <code>    </code><code>public</code> <code>void</code> <code>BuildHat()</code> <code>    </code><code>{</code> <code>        </code><code>throw</code> <code>new</code> <code>NotImplementedException();</code> <code>    </code><code>}</code> <code>    </code><code>/// 建構上衣</code> <code>    </code><code>public</code> <code>void</code> <code>BuilderWaist()</code> <code>    </code><code>/// 建構褲子</code> <code>    </code><code>public</code> <code>void</code> <code>BuilderTrousers()</code>
實作建立對象的具體步驟:
<code>public</code> <code>class</code> <code>Builder : IBuider</code> <code>     </code><code>private</code> <code>Dress _dress;</code> <code>     </code><code>public</code> <code>Builder(Dress dress)</code> <code>     </code><code>{</code> <code>         </code><code>this</code><code>._dress = dress;</code> <code>     </code><code>}</code> <code>    </code><code>public</code> <code>void</code> <code>BuilderPart1()</code> <code>        </code><code>this</code><code>._dress.BuildHat();</code> <code>    </code><code>public</code> <code>void</code> <code>BuilderPart2()</code> <code>        </code><code>this</code><code>._dress.BuilderWaist();</code> <code>    </code><code>public</code> <code>void</code> <code>BuilderPart3()</code> <code>        </code><code>this</code><code>._dress.BuilderTrousers();</code> <code>    </code><code>public</code> <code>Dress Build()</code> <code>        </code><code>return</code> <code>this</code><code>._dress;</code>
通過指導者指導對象的建立,而具體的對象的建立還是靠對象本身提供的相應方法,Builder隻是調用對象的方法完成組裝步驟。Builder内部提供一個傳回構造後完整對象的方法,上面給出的方法是 Build()方法。
<code>/// 指導者</code> <code>public</code> <code>class</code> <code>Director</code> <code>    </code><code>public</code> <code>void</code> <code>Build(IBuider builder)</code> <code>        </code><code>builder.BuilderPart1();</code> <code>        </code><code>builder.BuilderPart2();</code> <code>        </code><code>builder.BuilderPart3();</code>
通過上面的代碼,我們給出了經典建立者模式的核心代碼形式,那麼針對上面無疑有以下的幾個缺點: 1、Ibuilder接口必須定義完整的組裝流程,一旦定義就不能随意的動态修改。 2、Builder與具體的對象之間有一定的依賴關系,當然這裡可以通過接口來解耦來實作靈活性。 3、Builder必須知道具體的流程。 那麼針對上面的幾個問題,我們如何來解決呢?我想前面的建立型模式已經給我了足夠的經驗,還是通過配置檔案或者其他的形式來提供靈活性。
    我們先定義一個構造每個對象部分的委托,并且這個方法的參數是動态變化的:
<code>/// 定義通用的構造部分的委托</code> <code>public</code> <code>delegate</code> <code>void</code> <code>BuildHandler(</code><code>params</code> <code>object</code><code>[] items);</code>    我們通過定義标記來辨別對象中的每個部分的構造步驟
<code>/// 為對象中的每個步驟打上标記</code> <code>[AttributeUsage(AttributeTargets.Method,AllowMultiple=</code><code>false</code><code>)]</code> <code>public</code> <code>class</code> <code>BuildAttribute : Attribute</code> <code>    </code><code>private</code> <code>MethodInfo hander;</code> <code>    </code><code>private</code> <code>int</code> <code>stepSort;</code> <code>    </code><code>public</code> <code>MethodInfo BuildHandler</code> <code>        </code><code>get</code> <code>        </code><code>{</code> <code>            </code><code>return</code> <code>this</code><code>.hander;</code> <code>        </code><code>}</code> <code>        </code><code>set</code> <code>            </code><code>this</code><code>.hander = value;</code> <code>    </code><code>public</code> <code>int</code> <code>StepSort</code> <code>            </code><code>return</code> <code>this</code><code>.stepSort;</code> <code>            </code><code>this</code><code>.stepSort = value;</code> 構造對象的統一接口 <code>    </code><code>void</code> <code>Build&lt;T&gt;() </code><code>where</code> <code>T : </code><code>class</code><code>,</code><code>new</code><code>();</code> 下面給出具體的Builder的緩存實作方案代碼 <code>public</code> <code>class</code> <code>CommonBuilder : IBuider</code> <code>     </code><code>/// &lt;summary&gt;</code> <code>     </code><code>/// 緩存每個對象的具體的構造步驟</code> <code>     </code><code>/// &lt;/summary&gt;</code> <code>     </code><code>private</code> <code>Dictionary&lt;Type, List&lt;BuildHandler&gt;&gt; steps = </code><code>null</code><code>;</code> <code>    </code><code>public</code> <code>void</code> <code>Build&lt;T&gt;(T ob) </code><code>where</code> <code>T : </code><code>class</code><code>, </code><code>new</code><code>()</code> <code>        </code><code>//從緩存中讀取指定類型的項</code> <code>        </code><code>List&lt;BuildHandler&gt; handlers = steps[</code><code>typeof</code><code>(T)];</code> <code>        </code><code>foreach</code> <code>(BuildHandler handler </code><code>in</code> <code>handlers)</code> <code>            </code><code>handler();</code> 給出一些擷取某個類型内部的所有具有我們的自定義特性标記的MethodInfo清單 <code>public</code> <code>List&lt;MethodInfo&gt; GetMethodInfoList&lt;T&gt;() </code><code>where</code> <code>T : </code><code>class</code><code>, </code><code>new</code><code>()</code> <code>    </code><code>//從緩存中讀取指定類型的項</code> <code>    </code><code>List&lt;MethodInfo&gt; methods = </code><code>new</code> <code>List&lt;MethodInfo&gt;();</code> <code>    </code><code>T target = </code><code>new</code> <code>T();</code> <code>    </code><code>MethodInfo[] methodList= </code><code>typeof</code><code>(T).GetType().GetMethods();</code> <code>    </code><code>BuildAttribute[] attributes = </code><code>null</code><code>;</code> <code>    </code><code>foreach</code> <code>(MethodInfo info </code><code>in</code> <code>methodList)</code> <code>       </code><code>attributes=  (BuildAttribute[])info.GetCustomAttributes(</code><code>typeof</code><code>(BuildAttribute), </code><code>true</code><code>);</code> <code>       </code><code>if</code> <code>(attributes.Length &gt; 0)</code> <code>           </code><code>methods.Add(info);</code> <code>    </code><code>return</code> <code>methods;</code> 擷取所有的特性,一般使用這個方法即可擷取所有的具有标記該特性的方法清單和相應的步驟: <code>public</code> <code>List&lt;BuildAttribute&gt; GetBuildAttributeList&lt;T&gt;() </code><code>where</code> <code>T : </code><code>class</code><code>, </code><code>new</code><code>()</code> <code>  </code><code>{</code> <code>      </code><code>List&lt;BuildAttribute&gt; attributes = </code><code>new</code> <code>List&lt;BuildAttribute&gt;();</code> <code>      </code><code>BuildAttribute[] attributeList = </code><code>null</code><code>;</code> <code>      </code><code>BuildAttribute attribute = </code><code>null</code><code>;</code> <code>      </code><code>foreach</code> <code>(MethodInfo info </code><code>in</code> <code>this</code><code>.methods)</code> <code>      </code><code>{</code> <code>          </code><code>//設定特性中要執行的方法</code> <code>          </code><code>attributeList = (BuildAttribute[])info.GetCustomAttributes(</code><code>typeof</code><code>(BuildAttribute), </code><code>true</code><code>);</code> <code>          </code><code>if</code> <code>(attributeList.Length &gt; 0)</code> <code>          </code><code>{</code> <code>              </code><code>attribute = attributeList[0];</code> <code>              </code><code>attribute.BuildHandler = info;</code> <code>              </code><code>attributes.Add(attribute);</code> <code>          </code><code>}</code> <code>      </code><code>}</code> <code>      </code><code>//緩存步驟</code> <code>      </code><code>steps.Add(</code><code>typeof</code><code>(T), attributes);</code> <code>      </code><code>return</code> <code>attributes;</code> <code>  </code><code>}</code> 具體的Build中的調用代碼實作: <code>public</code> <code>T Build&lt;T&gt;(T ob) </code><code>where</code> <code>T : </code><code>class</code><code>, </code><code>new</code><code>()</code> <code> </code><code>{</code> <code>     </code><code>List&lt;BuildAttribute&gt; attributeList = GetBuildAttributeList&lt;T&gt;();</code> <code>     </code><code>T target=</code><code>new</code> <code>T();</code> <code>     </code><code>//構造對象的過程</code> <code>     </code><code>foreach</code> <code>(BuildAttribute item </code><code>in</code> <code>attributeList)</code> <code>         </code><code>item.BuildHandler.Invoke(target,</code><code>null</code><code>);</code> <code>     </code><code>return</code> <code>target;</code> <code> </code><code>}</code> 這樣我們就完成了一個通用的基于标記的自動發現某個類型的标記方法步驟的通用代碼實作,可能大家感覺這樣的方式還是挺麻煩的,那麼我們還有沒有更好的改進方案呢?因為每次打标記我還是感 覺挺麻煩的,而且代碼量分布的也比較廣泛,我想通過統一配置管理的方式,當然也是可以的,那麼我們可以通過下面的方式來進行擴充。
<a href="http://images.cnblogs.com/cnblogs_com/hegezhou_hot/Windows-Live-Writer/633b606b0863_B56F/image_7.png"></a> 我這裡給出配置檔案的父子級節點示例: <code>&lt;?</code><code>xml</code> <code>version</code><code>=</code><code>"1.0"</code> <code>encoding</code><code>=</code><code>"utf-8"</code> <code>?&gt;</code> <code>&lt;</code><code>Build</code><code>&gt;</code> <code>    </code><code>&lt;</code><code>BuildClass</code> <code>name</code><code>=</code><code>"ClassName"</code> <code>type</code><code>=</code><code>"ClassType"</code><code>&gt;</code> <code>        </code><code>&lt;</code><code>BuildStep</code> <code>StepOrder</code><code>=</code><code>"1"</code> <code>MethodName</code><code>=</code><code>"MethodName1"</code><code>/&gt;</code> <code>        </code><code>&lt;</code><code>BuildStep</code> <code>StepOrder</code><code>=</code><code>"2"</code> <code>MethodName</code><code>=</code><code>"MethodName2"</code> <code>/&gt;</code> <code>    </code><code>&lt;/</code><code>BuildClass</code><code>&gt;</code> <code>    </code><code>&lt;</code><code>BuildClass</code> <code>name</code><code>=</code><code>"ClassName1"</code> <code>type</code><code>=</code><code>"ClassType1"</code><code>&gt;</code> <code>&lt;/</code><code>Build</code><code>&gt;</code> 我們這裡通過在Build實作中讀取配置檔案中的所有的步驟,放在字典中。給出示例代碼 <code>public</code> <code>class</code> <code>Buider : IBuider</code> <code>    </code><code>private</code> <code>Dictionary&lt;Type, List&lt;MethodInfo&gt;&gt; steps = </code><code>null</code><code>;</code> <code>    </code><code>public</code> <code>Buider()</code> <code>        </code><code>steps = </code><code>new</code> <code>Dictionary&lt;Type, List&lt;MethodInfo&gt;&gt;();</code> <code>        </code><code>//讀取配置檔案!</code> <code>        </code><code>//将配置檔案中的類名和方法名取出,然後通過反射取到這個類型下的所有方法,根據配置中的步驟和方法名添加到</code> <code>        </code><code>//步驟清單中,然後緩存到字典中</code> <code>        </code><code>steps.Add(Type.GetType(</code><code>""</code><code>), </code><code>new</code> <code>List&lt;MethodInfo&gt;());</code> <code>    </code><code>public</code> <code>T Build&lt;T&gt;() </code><code>where</code> <code>T: </code><code>class</code><code>,</code><code>new</code><code>()</code> <code>        </code><code>T target = </code><code>new</code> <code>T();</code> <code>        </code><code>//從字典中找到對應的緩存清單,執行構造過程</code> <code>        </code><code>List&lt;MethodInfo&gt; list = steps[</code><code>typeof</code><code>(T)];</code> <code>        </code><code>//執行構造</code> <code>        </code><code>foreach</code> <code>(MethodInfo info </code><code>in</code> <code>list)</code> <code>            </code><code>info.Invoke(target, </code><code>null</code><code>);</code> <code>        </code><code>return</code> <code>target;</code> 通過上面的幾步配置就可以完成相應的建構過程,這時候我們的指導者的工作就簡單了,就是隻是簡單的通過使用Build中的通用方法 <code>    </code><code>public</code> <code>void</code> <code>Build&lt;T&gt;(IBuider builder) </code><code>where</code> <code>T:</code><code>class</code><code>,</code><code>new</code><code>()</code> <code>        </code><code>builder.Build&lt;T&gt;();</code> 隻要通過上面的步驟就完成了建立者模式的通用實作方案。
通過上面的給出的幾類不同的實作方案我們知道,建立者模式是一個對對象的建構過程“精細化”的建構過程,每個部分的建構可能是變化的,但是對象的組織過程是固定的,通過這種統一的建立方 式,無疑增加了我們設計上的靈活性,當我們在建構複雜對象的時候,我們如果發現每個部分可能都是變化的,并且是多個不同的建構步驟的時候,我們可以考慮使用建立者模式。相比我們之前講述 的工廠和抽象工廠模式差別還是很大的,我們發現建立者适合這類複雜對象的建立,對于抽象工廠可能就無法完成這樣的組裝工作,而且建立者模式是把複雜對象的内部建立方法進行調用,組織協調 了對象的各個部分前後順序的控制。簡單的描述建立者就是這樣的情況: <a href="http://images.cnblogs.com/cnblogs_com/hegezhou_hot/Windows-Live-Writer/633b606b0863_B56F/image_13.png"></a> 由于本人水準有限,或者講述能力有限,表達思路錯誤或者想法錯誤,請大家批評指出,如果您有更好的意見或者想法,請提出讨論,歡迎大家提出寶貴意見和建議。
      建立型         5、系統架構技能之設計模式-原型模式         結構型         1、系統架構技能之設計模式-組合模式         2、系統架構技能之設計模式-外觀模式         3、系統架構技能之設計模式-擴充卡模式         4、系統架構技能之設計模式-橋模式         5、系統架構技能之設計模式-裝飾模式         6、系統架構技能之設計模式-享元模式         7、系統架構技能之設計模式-代理模式         行為型         1、系統架構技能之設計模式-指令模式         2、系統架構技能之設計模式-觀察者模式         3、系統架構技能之設計模式-政策模式         4、系統架構技能之設計模式-職責模式         5、系統架構技能之設計模式-模闆模式         6、系統架構技能之設計模式-中介者模式         7、系統架構技能之設計模式-解釋器模式
下篇将會針對原型模式進行講述,該模式也是建立型模式中很有特點設計模式之一,該 模式是利用現有的一個對象進行克隆的過程産生一個新的對象,當然這裡的複制對象可以是2種,深複制和淺複 制,在這個系列的總結中如果您有好的想法或者創意,請提出來,希望大家多提寶貴意見,錯誤之處還請指出,請大家繼續支援。

本文轉自 hot的fans  51CTO部落格,原文連結:http://blog.51cto.com/2435232/440214

繼續閱讀