Design Patterns: Elements of Reusable Object-Oriented Software (ISBN 0-201-63361-2)是軟體工程領域有關軟體設計的一本書,提出和總結了對於一些常見軟體設計問題的標準解決方案,稱為軟體設計模式。該書作者為:Erich Gamma, Richard Helm, Ralph Johnson,John Vlissides,後以「四人幫」("Gang of Four")著稱。
設計模式並不直接用來完成程式碼的編寫,而是描述在各種不同情況下,要怎麼解決問題的一種方案。物件導向設計模式通常以類別或物件來描述其中的關係和相互作用,但不涉及用來完成應用程式的特定類別或物件。設計模式主要是使不穩定的 依賴於相對穩定、具體依賴於相對抽象,避免會引起麻煩的緊耦合,以增強軟體設計面對並適應變化的能力。
表述格式
表述一個軟體設計模式的格式根據作者的不同,劃分和名稱等都會有所不同。常用的GoF描述模式的格式大致分為以下這些部分:
- 模式名:每一個模式都有自己的名字,模式的名字使得我們可以討論我們的設計。
- 問題:在物件導向的系統設計過程中反覆出現的特定場合,它導致我們採用某個模式。
- 解決方案:上述問題的解決方案,其內容給出了設計的各個組成部分,它們之間的關係、職責劃分和協作方式。
- 別名:一個模式可以有超過一個以上的名稱。這些名稱應該要在這一節註明。
- 動機:該模式應該利用在哪種情況下是本節提供的方案(包括問題與來龍去脈)的責任。
- 適用性:模式適用於哪些情況、模式的背景等等。
- 結構:這部分常用類圖 與互動圖闡述此模式。
- 參与者:這部分提供一份本模式用到的類與物件清單,與它們在設計下 扮演的角色。
- 合作:描述在此模式下,類與物件間的互動。
- 影響:採用該模式對軟體系統其他部分的影響,比如對系統的擴充性、可移植性的影響。影響也包括負面的影響。這部分應描述使用本模式後 的結果、副作用、與權衡(trade-off)
- 實作:這部分應描述實現該模式、該模式的 部分方案、實現該模式的可能技術、或者建議實現模式的方法。
- 示例:簡略描繪出如何以程式 語言來使用模式。
- 已知應用:業界已知的實作範例。
- 相關模式:這部分包括其他相關模式,以及與其他類似模式的不同。
模式名稱 | 描述 |
---|---|
創建型模式 | |
抽象工廠模式 | 為一個產品族提供了統一的創建介 面。當需要這個產品族的某一系列的時候,可以從抽象工廠中選出相應的系列創建一個具體的工廠類。 |
工廠方法模式 | 定義一個介面用於創建對象,但是 讓子類決定初始化哪個類。工廠方法把一個類的初始化下放到子類。 |
生成器模式 | 將一個複雜對象的構建與它的表示分 離,使得同樣的構建過程可以創建不同的表示。 |
懶惰初始化模式 | 推遲對象的 創建、數據的計算等需要耗費較多資源的操作,只有在第一次訪問的時候才執行。 |
對象池模式 | 通過回收利用對象避 免獲取和釋放資源所需的昂貴成本。 |
原型模式 | 用原型實例指定創建對象的種類,並且通過 拷貝這些原型創建新的對象。 |
單例模式 | 確保一個類只有一個實例,並提供對該實例 的全局訪問。 |
結構型模式 | |
適配器模式 | 將某個類的介面轉換成客戶端期望的另 一個介面表示。適配器模式可以消除由於介面不匹配所造成的類兼容性問題。 |
橋接模式 | 將一個抽象與實現解耦,以便兩者可以獨立 的變化。 |
組合模式 | 把多個對象組成樹狀結構 來表示局部與整體,這樣用戶可以一樣的對待單個對象和對象的組合。 |
修飾模式 | 向某個對象動態地添加更多的功能。修飾模 式是除類繼承外另一種擴展功能的方法。 |
外觀模式 | 為子系統中的一組介面提供一個一致的界 面, 外觀模式定義了一個高層介面,這個介面使得這一子系統更加容易使用。 |
享元模式 | 通過共享以便有效的支持 大量小顆粒對象。 |
代理模式 | 為其他對象提供一個代理 以控制對這個對象的訪問。 |
行為模式 | |
責任鏈模式 | 為解除請求的發送者和接收者之間耦 合,而使多個對象都有機會處理這個請求。將這些對象連成一條鏈,並沿著這條鏈傳遞該請求,直到有一個對象處理它。 |
命令模式 | 將一個請求封裝為一個對象,從而使你可用 不同的請求對客戶進行參數化;對請求排隊或記錄請求日誌,以及支持可取消的操作。 |
解釋器模式 | 給定一個語言, 定義它的文法的一種表示,並定義一個解釋器, 該解釋器使用該表示來解釋語言中的句子。 |
迭代器模式 | 提供一種方法順序訪 問一個聚合對象中各個元素, 而又不需暴露該對象的內部表示。 |
Mediator | Define an object that encapsulates how a set of objects interact. Mediator promotes loose coupling by keeping objects from referring to each other explicitly, and it lets you vary their interaction independently. |
備忘錄模式 | Without violating encapsulation, capture and externalize an object's internal state so that the object can be restored to this state later. |
觀察者模式 | 在對象間定義一個一對多的聯繫性,由 此當一個對象改變了狀態,所有其他相關的對象會被通知並且自動刷新。 |
狀態模式 | Allow an object to alter its behavior when its internal state changes. The object will appear to change its class. |
策略模式 | 定義一個演算法的系列,將其各個分裝,並 且使他們有交互性。策略模式使得演算法在用戶使用的時候能獨立的改變。 |
Specification | Recombinable Business logic in a boolean fashion |
模板方法模式 | Define the skeleton of an algorithm in an operation, deferring some steps to subclasses. Template Method lets subclasses redefine certain steps of an algorithm without changing the algorithm's structure. |
訪問者模式 | Represent an operation to be performed on the elements of an object structure. Visitor lets you define a new operation without changing the classes of the elements on which it operates. |
Single-serving visitor | Optimize the implementation of a visitor that is allocated, used only once, and then deleted |
Hierarchical visitor | Provide a way to visit every node in a hierarchical data structure such as a tree. |
併發模式 | |
Active Object | |
Balking | |
Double checked locking | |
Guarded | |
Leaders/followers | |
Monitor object | |
Read write lock | |
Scheduler | |
執行緒池模式 | |
Thread-specific storage | |
Reactor |
MVC(Model-View-Controller,模型—檢視—控 制器模式)是軟體專案中的一種軟體架構模式。它把軟體系統分為三個基本部分:模型(Model),檢視(View)和控制器 (Controller)。
MVC最早由Trygve Reenskaug在1974年[1]提 出,是施樂帕羅奧多研究中心(Xerox PARC)在20世紀80年代為程式語言Smalltalk發明的一種軟體設計模式。模型—檢視—控制器模式的目的是實作一種動態 的程式設計,使後續對程式的修改和擴展簡化,並且使程式某一部分的重複利用成為可能。除此之外此模式透過對複雜度的簡化使程式結構更加直覺。軟體系統透過 對自身基本部份分離的同時也賦予了各個基本部分應有的功能。專業人員可以透過自身的專長分組:
- 控制器- 程式設計師編寫程式應有的功能(實作演算法等等)
- 檢視 - 介面設計人員進行圖形介面設計
- 模型 - 資料庫專家進行資料管理和資料庫設計
層次
模型(Model) 「資料模型」(Model)用於封裝與應用程式的業務邏輯相關的資料以及對資料的處理方法。「模型」有對資料直接存取的權利,例如對資料庫的存取。「模 型」不依賴「檢視」和「控制器」,也就是說,模型不關心它會被如何顯示或是如何被操作。但是模型中資料的變化一般會透過一種重新整理機制被公布。為了實作 這種機制,那些用於監視此模型的檢視必須事先在此模型上註冊,從而,檢視可以了解在資料模型上發生的改變。(比較:觀察者模式(軟體設計模式))
檢視(View) 檢視層能夠實作資料有目的的顯示(理論上,這不是必需的)。在檢視中一般沒有程式上的邏輯。為了實作檢視上的重新整理功能,檢視需要存取它監視的資料模型 (Model),因此應該事先在被它監視的資料那裡註冊。
控制器 (Controller) 控制器起到不同層面間的組織作用,用於控制應用程式的流程。它處理事件並作出響應。「事件」包括使用者的行為和資料模型上的改變。
優點
在最初的JSP網頁中,像資料庫查詢語句這樣的資料層代碼和像HTML這樣的表示層代碼混在一起。經驗比較豐富的開發者會將資料從表示層分離開來,但這通常不是很容易做到的,它需 要精心地計劃和不斷的嘗試。MVC從根本上強制性地將它們分開。儘管構造MVC應用程式需要一些額外的工作,但是它帶給我們的好處是毋庸置疑的。
首先,多個檢視能共享一個模型。如今,同一個Web應用程式會提供多種使用者介面,例如使用者希望既能夠透過瀏覽器來收發電子郵件,還希望透過手機來存取電子郵箱,這就要求Web網站同時能提供Internet介面和WAP介面。在MVC設計模式中,模型響應使用者請求並返迴響應資料,檢視負責格式化資料並把它們呈現給使用者,業務邏 輯和表示層分離,同一個模型可以被不同的檢視重用,所以大大提高了代碼的可重用性。
其次,模 型是自包含的,與控制器和檢視保持相對獨立,所以可以方便的改變應用程式的資料層和業務規則。如果把資料庫從MySQL移植到Oracle,或者把RDBMS資料源改變成LDAP資料源,只需改變模型即可。一旦正確地實作了模型,不管書庫來自資料庫還是LDAP伺服器,檢視都會正確地顯示它們。由於MVC的三個模組相互獨立,改變其中一個不會影響其他兩個,所以依據這 種設計思想能構造良好的松耦合的構件。
此外,控制器提高了應用程式的靈活性和可配置性。控制 器可以用來連線不同的模型和檢視去完成使用者的需求,也可以構造應用程式提供強有力的手段。給 定一些可重用的模型和檢視,控制器可以根據使用者的需求選擇適當的模型機型處理,然後選擇適當的的檢視將處理結果顯示給使用者。
缺點及適用範圍
MVC的缺點是由於它沒有明確的定義,所以完全理解MVC並不是很容易。使用MVC需要精心的計劃,由於它的內部原理比較複雜,所以需 要花費一些時 間去思考。開發一個MVC架構的專案,將不得不花費相當可觀的時間去考慮如何將MVC運用到應用程式中,同時由於模型和檢視要嚴格的分離,這樣也給偵錯應 用程式帶來了一定的困難。每個構件在使用之前都需要經過徹底的測試。另外由於MVC將一個應用程式分成了三個部件,所以這意味著同一個專案將包含比以前更 多的檔案。
因此MVC並不適合小型甚至中等規模的應用程式,這樣會帶來額外的工作量,增加 應用的複雜性。但對於開發存在大量使用者介面,並且邏輯複雜的大型應 用程式,MVC將會使軟體在健壯性、代碼重用和結構方面上一個新的台階。儘管在最初構建MVC框架時會花費一定的工作量,但從長遠的角度來看,它會大大提 高後期軟體開發的效率。
生成器模式(Builder Pattern)
因為想到 原本製作的電子鼓視覺化的程式,每一擊都會產生一個圖像,如果能讓圖像變成物件,就可以再針對那些產生的物件做進一步的控制。所以看到Builder Pattern,感覺好像可以達到我的目標,於是將它記錄下來。
- Builder
- ConcreteBuilder
- Director
- Product
Java Example
/** "Product" */
class Pizza {
private String dough = "";
private String sauce = "";
private String topping = "";
public void setDough (String dough) { this.dough = dough; }
public void setSauce (String sauce) { this.sauce = sauce; }
public void setTopping (String topping) { this.topping = topping; }
}
/** "Abstract Builder" */
abstract class PizzaBuilder {
protected Pizza pizza;
public Pizza getPizza() { return pizza; }
public void createNewPizzaProduct() { pizza = new Pizza(); }
public abstract void buildDough();
public abstract void buildSauce();
public abstract void buildTopping();
}
/** "ConcreteBuilder" */
class HawaiianPizzaBuilder extends PizzaBuilder {
public void buildDough() { pizza.setDough("cross"); }
public void buildSauce() { pizza.setSauce("mild"); }
public void buildTopping() { pizza.setTopping("ham+pineapple"); }
}
/** "ConcreteBuilder" */
class SpicyPizzaBuilder extends PizzaBuilder {
public void buildDough() { pizza.setDough("pan baked"); }
public void buildSauce() { pizza.setSauce("hot"); }
public void buildTopping() { pizza.setTopping("pepperoni+salami"); }
}
/** "Director" */
class Waiter {
private PizzaBuilder pizzaBuilder;
public void setPizzaBuilder (PizzaBuilder pb) { pizzaBuilder = pb; }
public Pizza getPizza() { return pizzaBuilder.getPizza(); }
public void constructPizza() {
pizzaBuilder.createNewPizzaProduct();
pizzaBuilder.buildDough();
pizzaBuilder.buildSauce();
pizzaBuilder.buildTopping();
}
}
/** A customer ordering a pizza. */
class BuilderExample {
public static void main(String[] args) {
Waiter waiter = new Waiter();
PizzaBuilder hawaiian_pizzabuilder = new HawaiianPizzaBuilder();
PizzaBuilder spicy_pizzabuilder = new SpicyPizzaBuilder();
waiter.setPizzaBuilder ( hawaiian_pizzabuilder );
waiter.constructPizza();
Pizza pizza = waiter.getPizza();
}
}