1. 程式人生 > >10分鐘看懂常用設計模式

10分鐘看懂常用設計模式

    前面的文章中,對常用的設計模式做了通俗的介紹,每篇中從問題的引入,到一般實現辦法,到模式解決辦法,最後分析模式的優缺點和適用場景。本片文章將對這些設計模式分類、對比,並將相似模式放在一起做適用分析。     首先,設計模式是什麼?它並不是由誰發明出來的一種技術,而是程式設計發展以來,人們在實際的開發中總是能遇到區域性相似的一些問題,針對這些問題的相對好的解決經驗進行提煉,提出了一套模式。類似於初等數學中,某一類的問題當你做的多了,自然就有了一套相對通用的解決方法,這個設計模式的道理是一樣的。通過前面的介紹,可以看出大多數的模式都是基於面向物件的思想,也可以說設計模式的面向物件發展過程中,前人提煉出來的寶貴經驗。模式不是固定不變的,因為問題複雜多變,沒有絕對通用的辦法。我們在解決問題的時候也會根據實際的情況做一些變通,但是設計模式為我們提供了寶貴的思路:怎樣讓你的程式更加的優雅、健壯。當養成了這種思維,脫離模式的設計反而是更上一個境界,這就是武學中的無招勝有招。但是在基本功不是很強的時候,老老實實的扎馬步、練拳,永遠是一個好的途徑。     設計模式可分為建立型(Creational),結構型(Structural)和行為型(Behavioral)三種,其中建立型模式主要用於描述如何建立物件結構型模式主要用於描述如何實現類或物件的組合行為型模式主要用於描述類或物件怎樣互動以及怎樣分配職責。

 建立型

    很明顯,工廠模式、原型模式、建造者模式、單例模式這幾個是建立型模式。這裡的工廠模式又包括了:簡單工廠、工廠方法、抽象工廠這三種。

工廠三兄弟:簡單工廠提供了最簡單工廠模型,將所有類物件的建立邏輯封裝在一個工廠類中。避免了在使用的地方到處的new和初始化,但是弊端是職責過重,不符合開閉。工廠方法為了解決上面的問題,為工廠也進行了分級,每個產品對應了一個工廠。但是弊端是工廠過多,編碼的負擔增重。抽象工廠是針對存在產品系列(產品簇)的情況,即當產品中,可以按照一定維度將同等級的不同產品組合在一起形成一個系列時,我們只為整個系列建立一個工廠。這樣既解決簡單工廠的職責過重,又減少了工廠方法方法的類數量。

原型模式:當一類物件有一個或者少數幾個固定的初始狀態,或某類物件的初始狀態可能執行時改變時,可以使用原型模式。通過儲存包含這些初始狀態的原型物件,然後clone得到一模一樣的新物件。

建造者模式:當一個複雜的物件是由多個具有不同具體類別的元件組成時,建造者模式可以使客戶端指定一個總類別,然後透明的建造出最終物件提供給客戶端。而且擴充套件新的組合時,負責開閉原則。如果元件間有一定的順序依賴邏輯,該模式可以在抽象建造者中定義這種先後規則。

單例模式:保持只有一個例項存在於系統中。

結構型

介面卡:當已有的或外部提供的某個介面、功能模組,和現有的設計、系統不匹配,而無法直接對接使用時,可以提供一個抽象的介面卡。然後具體的介面卡實現它,在具體的介面卡中再對需要被適配的介面進行包裝呼叫,從而達到間接使用的目的。

    代理模式:代理模式是在被訪問類前加上一個代理,對該類的例項的訪問,都要經過代理的控制和限制。單客戶端要可以透明的訪問被代理的物件。可以通過代理類和被代理類實現相同介面/繼承相同的抽象實現。

    裝飾模式:裝飾模式是在原油類的基礎上,額外的增加一些新的職責和功能。也要客戶端透明的使用,所以同樣實現相同的抽象。

    門面模式:如果一個系統內部的邏輯都對外暴露使用,將會使之與外部的耦合度增加,擴充套件/修改困難。可以通過一個門面對外提供統一的服務,實質就是將內部邏輯封裝在自己的範圍內,做到解耦/隔離。同時,門面也要做到針對抽象,才能更好的應對變化。

 以上四個模式在幾個方面具有有很大的相似性,但是仔細分析沒一個模式的用途,就很好辨別。他們乍看上去,都是為已有的東西提供了一個新的訪問途徑,但是目的卻都是不同的。介面卡是為了將不相容的東西連線到一起,改變了訪問方式。門面模式也改變了訪問方式,缺是為了將複雜的邏輯封裝解耦。代理和裝飾都是不改變訪問方式,透明的使用,但是代理是為了對原有的功能進行控制/限制,而裝飾模式是為了增加新的功能和職責,可以巢狀裝飾。

    橋接模式: 適用於系統中的某類實體,存在多個維度的變化因素。將各個維度的抽象類組合成產品,動態的組合不同的實現類,來達到靈活的產生不同的結果。例如有兩個維度,可以將一個維度用繼承實現,另一個維度用”被繼承的抽象父類“持有抽象介面類別的成員實現。多維度變化可以用同樣的思想,變通實現。

    組合模式:當一個系統內的一個元素集合的邏輯結構是一個樹形結構,既葉子結點都是不可分元素,而非葉子結點是若干節點的集合。例如集團下有CEO/董事/子公司。子公司就是集合,下面繼續包含元素。通過各種元素都整合一個抽象父類,可以實現統一管理,靈活的配置。

    享元模式:當系統中有一些經常重複用到的小粒度元素存在時,可以將這些元素的不可變部分分離出來成為享元,在系統中快取起來。這樣每次用到的地方只需給予一個享元的引用,大大減少了記憶體佔用。但是將類別抽象出可變與不可變(內部狀態與外部狀態)是不太容易的。

    行為型

    責任鏈模式:如果一個事件或訊息,不只有一個處理者,而是一系列有先後甚至分支關係的處理者鏈,可以用責任鏈模式。抽象的處理者維護一個或多個下一級的處理者。客戶端將事件交給一個入口後,就可以按照規則傳遞下去處理。可以靈活的組織成各種複雜的樹形/網形的處理模型。

    命令模式:將請求或事件例項化成物件,將呼叫替換成物件的傳遞,這個做法可以做到很多事情。例如,請求的排隊/持久化/非同步化/log/操作備份/資料恢復/操作撤銷等等。結合組合模式,可以實現巨集命令,組合成許多複雜的功能。

    迭代器模式:物件內包含若干元素的集合,需要對外部提供遍歷的服務。迭代器模式將遍歷的邏輯與原邏輯隔離開,保持簡單。同時兩者都互相持有對方抽象類,可以做到自由的組合切換,增加靈活性和複用性。

    中介者模式:在曾經的遊戲前端開發過程中,一件事很困擾我:多數使用者行為影響的不止是一個實體,而是多個有關聯的元件。他們之間牽一髮動全身,可以使用中介中模式作為這些關係的統一管理者,針對每個行為對相關聯的元件做出通知和調節,而不是每個元件的每個行為都去挨個通知關聯的元件的相關處理方法,這樣將網狀結構iy變成了星狀結構,更便於管理維護。更適用於複雜糾結的依賴關係。通過將元件統一抽象,將使中介者邏輯更加靈活,方便擴充套件。

    備忘錄模式:某些特殊類的例項需要儲存它們的歷史狀態,以便恢復/拷貝/持久化等等。備忘錄模式通過提供備忘錄類記錄物件需要被記錄的元素,儲存狀態。再通過備忘錄管理類管理這些狀態,提供訪問途徑。

    觀察者模式:當一類物件的改變被多個其他的例項依賴時,將這些依賴物件稱為觀察者,被觀察的物件維護觀察者的一個集合,當放生事件時,主動的去通知觀察者。

    模板方法模式:系統中總會有一些東西被無奈的按照一定的套路重複,實際可能每次不同的僅僅是其中一小部分。腦海裡瞬間浮現JDBC。模板方法模式在抽象父類中規定了這些繁瑣的規則,只將需要定製的部分留給實現類。極大的方便了客戶端簡潔的使用。利用鉤子方法,又可以給予客戶端一定的自由去控制這個規則,但是一切都是可控的。Spring在許多方面都利用了這個模式。腦海中瞬間又是JDBC。

    狀態模式:某類實體可能根據屬性具有多種不同的內部狀態,並需要即時的動態切換。狀態模式通過建立抽象狀態類將狀態與實體隔離,並可以靈活的切換和複用。

    策略模式:與狀態模式類似,只不過狀態模式是抽象出狀態,而策略模式是抽象出行為。將某個具有多種選擇的行為進行抽象隔離,實現動態切換和複用。

    訪問者模式:系統產生一系列的資訊,資訊可能有多種細分型別,這些資訊從不同層面分析具有多種價值,需要被多個不同目的邏輯處理。訪問者模式將資訊和訪問邏輯分別抽象,可以將資訊的出生與處理隔離,同時靈活的配置和切換處理的方案。又防止了多種邏輯混在一起的混亂。