Design Pattern

Design Pattern
Design Patterns: Elements of Reusable Object-Oriented Software (ISBN 0-201-63361-2)是軟體工程領域有關軟體設計的一本書,提出和總結了對於一些常見軟體設計問題的標準解決方案,稱為軟體設計模式。該書作者為:Erich Gamma, Richard Helm, Ralph JohnsonJohn Vlissides,後以「四人幫」("Gang of Four")著稱。
設計模式並不直接用來完成程式碼的編寫,而是描述在各種不同情況下,要怎麼解決問題的一種方案。物件導向設計模式通常以類別物件來描述其中的關係和相互作用,但不涉及用來完成應用程式的特定類別或物件。設計模式主要是使不穩定的 依賴於相對穩定、具體依賴於相對抽象,避免會引起麻煩的緊耦合,以增強軟體設計面對並適應變化的能力。

表述格式

表述一個軟體設計模式的格式根據作者的不同,劃分和名稱等都會有所不同。常用的GoF描述模式的格式大致分為以下這些部分:

  • 模式名:每一個模式都有自己的名字,模式的名字使得我們可以討論我們的設計。
  • 問題:在物件導向的系統設計過程中反覆出現的特定場合,它導致我們採用某個模式。
  • 解決方案:上述問題的解決方案,其內容給出了設計的各個組成部分,它們之間的關係、職責劃分和協作方式。
  • 別名:一個模式可以有超過一個以上的名稱。這些名稱應該要在這一節註明。
  • 動機:該模式應該利用在哪種情況下是本節提供的方案(包括問題與來龍去脈)的責任。
  • 適用性:模式適用於哪些情況、模式的背景等等。
  • 結構:這部分常用類圖 與互動圖闡述此模式。
  • 參与者:這部分提供一份本模式用到的類與物件清單,與它們在設計下 扮演的角色。
  • 合作:描述在此模式下,類與物件間的互動。
  • 影響:採用該模式對軟體系統其他部分的影響,比如對系統的擴充性、可移植性的影響。影響也包括負面的影響。這部分應描述使用本模式後 的結果、副作用、與權衡(trade-off)
  • 實作:這部分應描述實現該模式、該模式的 部分方案、實現該模式的可能技術、或者建議實現模式的方法。
  • 示例:簡略描繪出如何以程式 語言來使用模式。
  • 已知應用:業界已知的實作範例。
  • 相關模式:這部分包括其他相關模式,以及與其他類似模式的不同。

模式名稱描述
創建型模式
抽象工廠模式為一個產品族提供了統一的創建介 面。當需要這個產品族的某一系列的時候,可以從抽象工廠中選出相應的系列創建一個具體的工廠類。
工廠方法模式定義一個介面用於創建對象,但是 讓子類決定初始化哪個類。工廠方法把一個類的初始化下放到子類。
生成器模式將一個複雜對象的構建與它的表示分 離,使得同樣的構建過程可以創建不同的表示。
懶惰初始化模式推遲對象的 創建、數據的計算等需要耗費較多資源的操作,只有在第一次訪問的時候才執行。
對象池模式通過回收利用對象避 免獲取和釋放資源所需的昂貴成本。
原型模式用原型實例指定創建對象的種類,並且通過 拷貝這些原型創建新的對象。
單例模式確保一個類只有一個實例,並提供對該實例 的全局訪問。
結構型模式
適配器模式將某個類的介面轉換成客戶端期望的另 一個介面表示。適配器模式可以消除由於介面不匹配所造成的類兼容性問題。
橋接模式將一個抽象與實現解耦,以便兩者可以獨立 的變化。
組合模式把多個對象組成樹狀結構 來表示局部與整體,這樣用戶可以一樣的對待單個對象和對象的組合。
修飾模式向某個對象動態地添加更多的功能。修飾模 式是除類繼承外另一種擴展功能的方法。
外觀模式為子系統中的一組介面提供一個一致的界 面, 外觀模式定義了一個高層介面,這個介面使得這一子系統更加容易使用。
享元模式通過共享以便有效的支持 大量小顆粒對象。
代理模式為其他對象提供一個代理 以控制對這個對象的訪問。
行為模式
責任鏈模式為解除請求的發送者和接收者之間耦 合,而使多個對象都有機會處理這個請求。將這些對象連成一條鏈,並沿著這條鏈傳遞該請求,直到有一個對象處理它。
命令模式將一個請求封裝為一個對象,從而使你可用 不同的請求對客戶進行參數化;對請求排隊或記錄請求日誌,以及支持可取消的操作。
解釋器模式給定一個語言, 定義它的文法的一種表示,並定義一個解釋器, 該解釋器使用該表示來解釋語言中的句子。
迭代器模式提供一種方法順序訪 問一個聚合對象中各個元素, 而又不需暴露該對象的內部表示。
MediatorDefine 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.
策略模式定義一個演算法的系列,將其各個分裝,並 且使他們有交互性。策略模式使得演算法在用戶使用的時候能獨立的改變。
SpecificationRecombinable 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 visitorOptimize the implementation of a visitor that is allocated, used only once, and then deleted
Hierarchical visitorProvide 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發明的一種軟體設計模式。模型—檢視—控制器模式的目的是實作一種動態 的程式設計,使後續對程式的修改和擴展簡化,並且使程式某一部分的重複利用成為可能。除此之外此模式透過對複雜度的簡化使程式結構更加直覺。軟體系統透過 對自身基本部份分離的同時也賦予了各個基本部分應有的功能。專業人員可以透過自身的專長分組:

  • 控制器- 程式設計師編寫程式應有的功能(實作演算法等等)
  • 檢視 - 介面設計人員進行圖形介面設計
  • 模型 - 資料庫專家進行資料管理和資料庫設計

File:ModelViewControllerDiagramZh.png


層次

模型(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 Structure

  • Builder
為創建一個Product對象的各個部件指定抽象介面。
  • ConcreteBuilder
實現Builder的介面以構造和裝配該產品的各個部件。定義並明確它所創建的表示。提供一個檢索產品的介面
  • Director
構造一個使用Builder介面的對象。
  • Product
表示被構造的複雜對象。ConcreateBuilder創建該產品的內部表示並定義它的裝配過程。包含定義組成部件的類,包括將這些部件裝配成最終產品 的介面。



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();
}
}