設(shè)計(jì)模式問(wèn)答(一)

設(shè)計(jì)模式問(wèn)答(一)

什么是設(shè)計(jì)模式?您能說(shuō)出工廠(chǎng)模式、抽象工廠(chǎng)模式、創(chuàng)建者模式、原型模式、原型模式的潛復(fù)制及深復(fù)制、單例模式、命令模式的原理嗎?

簡(jiǎn)介

這是一個(gè)小巧的設(shè)計(jì)模式常見(jiàn)問(wèn)題問(wèn)答。在本節(jié)我們將一起探討工廠(chǎng)模式、抽象工廠(chǎng)模式、創(chuàng)建者模式、原型模式、原型模式的淺復(fù)制及深復(fù)制、單例模式、命令模式的原理。

在下面的鏈接中您可以閱讀設(shè)計(jì)模式常見(jiàn)問(wèn)題問(wèn)答的后續(xù)部分 :-

設(shè)計(jì)模式 FAQ’s 2 ---解釋器模式、迭代器模式、調(diào)停者模式、備忘錄模式、觀(guān)察者模式(http://www.codeproject.com/KB/aspnet/SoftArch2.aspx)

設(shè)計(jì)模式 FAQ’s 3 ---狀態(tài)模式、策略模式、訪(fǎng)問(wèn)者模式、適配器模式、享元模式 (http://www.codeproject.com/KB/aspnet/SoftArch3.aspx)

設(shè)計(jì)模式 FAQ’s 4 ---橋接模式、組合模式、裝飾器模式、門(mén)面模式、責(zé)任鏈模式、代理模式、模板模式( http://www.codeproject.com/KB/aspnet/SoftArch4.aspx)

什么是設(shè)計(jì)模式?

設(shè)計(jì)模式是給定的上下文中重復(fù)出現(xiàn)問(wèn)題的解決方案。所以基本上一個(gè)解決方案能處理同一類(lèi)型的問(wèn)題。設(shè)計(jì)模式應(yīng)該在軟件開(kāi)發(fā)的初始階段以適當(dāng)?shù)男问酱嬖凇1热缯f(shuō),您想實(shí)現(xiàn)一個(gè)排序算法并首先想到了冒泡排序。所以問(wèn)題就是如何實(shí)現(xiàn)排序,解決方案是冒泡排序。設(shè)計(jì)模式也是如此。

設(shè)計(jì)模式主要有哪三種分類(lèi)?

設(shè)計(jì)模式有三種基本類(lèi)別:創(chuàng)建型模式、結(jié)構(gòu)型模式和行為型模式

創(chuàng)建型模式:

抽象工廠(chǎng)模式:為一組類(lèi)創(chuàng)建實(shí)例。

建造者模式:將對(duì)象的構(gòu)造和表現(xiàn)分離開(kāi)來(lái)。

工廠(chǎng)方法模式:為多個(gè)派生類(lèi)創(chuàng)建一個(gè)實(shí)例。

原型模式:一個(gè)完全初始化對(duì)象實(shí)例的拷貝或克隆。

單例模式:只有一個(gè)實(shí)例存在的類(lèi)。

注意記住創(chuàng)建型模式最好的方式是謹(jǐn)記ABFPS (Abraham Became FirstPresident of States 亞伯拉罕成為國(guó)家第一任總統(tǒng))

結(jié)構(gòu)型模式

適配器模式:匹配不同接口的類(lèi)。

橋接模式:將一個(gè)對(duì)象的抽象部分從實(shí)現(xiàn)中分離出來(lái)。

組合模式:樹(shù)結(jié)構(gòu)的簡(jiǎn)單和復(fù)合對(duì)象。

裝飾器模式:為對(duì)象動(dòng)態(tài)添加職責(zé)。

門(mén)面模式:一個(gè)代表整個(gè)系統(tǒng)的類(lèi)。

享元模式:用來(lái)細(xì)粒度的高效共享實(shí)例。

代理模式:用一個(gè)對(duì)象表示另一個(gè)對(duì)象。

行為型模式

調(diào)停者模式:定義了簡(jiǎn)化類(lèi)和類(lèi)之間的交互。

備忘錄模式:捕獲和恢復(fù)一個(gè)對(duì)象的內(nèi)部狀態(tài)。

解釋器模式:將語(yǔ)言元素包含在一個(gè)程序中的一種方式。

迭代器模式:按順序訪(fǎng)問(wèn)集合中的元素。

職責(zé)鏈模式:在一連串對(duì)象中傳遞氣球的一種方式。

命令模式:將一個(gè)請(qǐng)求封裝成一個(gè)對(duì)象。

狀態(tài)模式:當(dāng)一個(gè)對(duì)象狀態(tài)發(fā)生變化時(shí)選擇該對(duì)象的一種行為。

策略模式:將一個(gè)算法封裝到一個(gè)類(lèi)之中。

觀(guān)察者模式:一種通知若干類(lèi)發(fā)生變化的機(jī)制。

模版方法模式:推遲具體步驟的算法到子類(lèi)中。

訪(fǎng)問(wèn)者模式:在類(lèi)不變的情況下定義一個(gè)新的操作。

你能否解釋清楚工廠(chǎng)模式?

工廠(chǎng)模式屬于創(chuàng)建型模式。這你可以從名字中“工廠(chǎng)”兩字看得出來(lái),它意味這構(gòu)造或者創(chuàng)建一些東西。在軟件架構(gòu)的范疇工廠(chǎng)模式意味著集中創(chuàng)建一些對(duì)象。下面是客戶(hù)不同類(lèi)型的發(fā)票的代碼片段,這些發(fā)票的創(chuàng)建依賴(lài)于客戶(hù)端指定的發(fā)票類(lèi)型。以下代碼有兩個(gè)問(wèn)題:

首先,我們有很多“new”關(guān)鍵字散落在客戶(hù)端。換句話(huà)說(shuō),客戶(hù)端加載時(shí)有肯多創(chuàng)建對(duì)象的過(guò)程使得客戶(hù)端邏輯變得非常復(fù)雜。

其次,客戶(hù)端需要知道所有的發(fā)票類(lèi)型。所以,如果我們我們要添加一種新的發(fā)票類(lèi)型如“InvoiceWithFooter”,那么客戶(hù)端需要引入新的類(lèi)并且需要重新編譯。

圖1:不同類(lèi)型的發(fā)票

以這些問(wèn)題作為基礎(chǔ),現(xiàn)在我們將看看工廠(chǎng)模式如何幫我們解決問(wèn)題。下圖中“工廠(chǎng)模式”展示的了兩個(gè)具體類(lèi)‘ClsInvoiceWithHeader’和‘ClsInvoiceWithOutHeader’。

第一個(gè)問(wèn)題是這些類(lèi)直接和客戶(hù)端有聯(lián)系導(dǎo)致了客戶(hù)端代碼中散落了很多“new”關(guān)鍵字。這個(gè)問(wèn)題通過(guò)引入一個(gè)新的類(lèi)‘ClsFactoryInvoice’來(lái)做所有創(chuàng)建對(duì)象的工作來(lái)解決。

第二個(gè)問(wèn)題是客戶(hù)端代碼知道所有具體類(lèi),如‘ClsInvoiceWithHeader’和‘ClsInvoiceWithOutHeader’。這導(dǎo)致了增加新的發(fā)票類(lèi)型時(shí)需要重新編譯客戶(hù)端代碼,例如如果增加‘ClsInvoiceWithFooter’類(lèi)型的發(fā)票,客戶(hù)端代碼需要改變并重新編譯。為了解決這個(gè)問(wèn)題我們引入了一個(gè)通用接口‘IInvoice’,兩個(gè)具體類(lèi)‘ClsInvoiceWithHeader’和‘ClsInvoiceWithOutHeader’都繼承并實(shí)現(xiàn)‘IInvoice’接口。

客戶(hù)端只需要引用‘IInvoice’接口,這使得客戶(hù)端和具體類(lèi)(‘ClsInvoiceWithHeader’和‘ClsInvoiceWithOutHeader’)0關(guān)聯(lián)。所以現(xiàn)在當(dāng)我們?cè)偃ヌ砑有碌陌l(fā)票類(lèi)時(shí)客戶(hù)端不需要做任何改動(dòng)。

在創(chuàng)建對(duì)象的那行只需要關(guān)注‘ClsFactoryInvoice’即可,這樣客戶(hù)端通過(guò)只關(guān)注‘IInvoice’接口取消了與具體類(lèi)的關(guān)聯(lián)。

圖2:工廠(chǎng)模式

以下是用C#實(shí)現(xiàn)的工廠(chǎng)模式代碼片段。為了避免重新編譯客戶(hù)端我們引入了‘IInvoice’發(fā)票接口。‘ClsInvoiceWithOutHeaders’和‘ClsInvoiceWithHeader’都實(shí)現(xiàn)該接口。

圖3:接口和具體類(lèi)

我們還引入了一個(gè)額外的包含getInvoice()方法的類(lèi)‘ClsFactoryInvoice’,該類(lèi)會(huì)根據(jù)發(fā)票類(lèi)型來(lái)生成發(fā)票對(duì)象。簡(jiǎn)而言之,我們將創(chuàng)建對(duì)象的邏輯集中在了‘ClsFactoryInvoice’中;客戶(hù)端只需要調(diào)用‘getInvoice’方法就可以生成發(fā)票對(duì)象。其中最重要的一點(diǎn)需要注意的是客戶(hù)端只引用‘IInvoice’類(lèi)型并且工廠(chǎng)類(lèi)‘ClsFactoryInvoice’同樣只返回‘IInvoice’類(lèi)型的引用。這有助于客戶(hù)端從具體類(lèi)中解耦,因此,當(dāng)我們新加發(fā)票類(lèi)型對(duì)應(yīng)的類(lèi)時(shí)不需要重新編譯客戶(hù)端。

圖4:生成發(fā)票的工廠(chǎng)類(lèi)

你能否解釋清楚抽象工廠(chǎng)模式?

抽象工廠(chǎng)擴(kuò)展了基本工廠(chǎng)模式。抽象工廠(chǎng)模式幫助我們將相似的工廠(chǎng)模式類(lèi)集中到一個(gè)統(tǒng)一的接口下。所以現(xiàn)在基本上所有常見(jiàn)的工廠(chǎng)模式都繼承自一個(gè)通用的抽象工廠(chǎng)類(lèi)來(lái)將他們統(tǒng)一到一個(gè)共同類(lèi)中。其他和工廠(chǎng)模式相關(guān)的東西都和之前討論的一樣。

一個(gè)工廠(chǎng)類(lèi)幫助我們將類(lèi)的創(chuàng)建和類(lèi)型集中起來(lái)。抽象工廠(chǎng)模式幫助我們形成相關(guān)工廠(chǎng)模式之間的一致性從而為客戶(hù)端提供更簡(jiǎn)單的接口。

圖5:抽象工廠(chǎng)結(jié)合相關(guān)工廠(chǎng)模式

現(xiàn)在既然我們已經(jīng)知道基本要素那么讓我們嘗試來(lái)理解抽象工廠(chǎng)模式的實(shí)現(xiàn)細(xì)節(jié)。如之前所說(shuō),我們通過(guò)繼承將工廠(chǎng)模式類(lèi)(factory1和factory2)綁定至一個(gè)共同的抽象工廠(chǎng)(AbstractFactory接口)。工廠(chǎng)類(lèi)位于具體類(lèi)之上,再次從共同接口中推導(dǎo)。例如圖“實(shí)現(xiàn)抽象工廠(chǎng)”中具體類(lèi)‘product1’和‘product2’都繼承自同一個(gè)接口,如‘common’。而需要使用具體類(lèi)的客戶(hù)端只需要和抽象工廠(chǎng)以及具體類(lèi)所實(shí)現(xiàn)的抽象接口交互即可。

圖6:實(shí)現(xiàn)抽象工廠(chǎng)

現(xiàn)在我們來(lái)看看如何在實(shí)際代碼中實(shí)現(xiàn)抽象工廠(chǎng)模式。我們有一個(gè)場(chǎng)景是在ui對(duì)象創(chuàng)建中我們需要通過(guò)文本框(textbox)和按鈕(button)各自的中心化工廠(chǎng)類(lèi)‘ClsFactoryButton’和‘ClsFactoryText’來(lái)創(chuàng)建各自對(duì)象。這兩個(gè)類(lèi)都繼承自同一個(gè)接口‘InterfaceRender’;并且兩個(gè)工廠(chǎng)類(lèi)都繼承自共同的工廠(chǎng)類(lèi)‘ClsAbstractFactory’。圖“抽象工廠(chǎng)例子”中展示了這類(lèi)的關(guān)系以及客戶(hù)端代碼是相同的。其中重要的一點(diǎn)是客戶(hù)端代碼不需要與具體類(lèi)交互。對(duì)于對(duì)象的創(chuàng)建,客戶(hù)端使用抽象工廠(chǎng)類(lèi)(ClsAbstractFactory),而調(diào)用具體類(lèi)則通過(guò)調(diào)用接口‘InterfaceRender’中的共用方法來(lái)完成。因此‘ClsAbstractFactory’類(lèi)為‘ClsFactoryButton’和‘ClsFactoryText’的工廠(chǎng)類(lèi)提供了共同的抽象接口。

圖7:抽象工廠(chǎng)例子

下面我們將運(yùn)行例子中抽象工廠(chǎng)的代碼。下圖“抽象工廠(chǎng)和工廠(chǎng)代碼快照”中的代碼快照展示的工廠(chǎng)模式類(lèi)與抽象工廠(chǎng)的繼承關(guān)系。

圖8:抽象工廠(chǎng)和工廠(chǎng)代碼快照

圖“具體類(lèi)通用接口”展示了具體類(lèi)和通用接口‘InterFaceRender’的繼承關(guān)系,其中‘InterFaceRender’接口為所有具體類(lèi)強(qiáng)制增加‘render’方法。

圖9:通用接口

最后要做的事情就是客戶(hù)端通過(guò)使用‘InterfaceRender’接口和‘ClsAbstractFactory’抽象工廠(chǎng)來(lái)調(diào)用和創(chuàng)建對(duì)象。其中關(guān)鍵要素是該代碼完全和具體類(lèi)隔離。所以任何具體類(lèi)的變化如增加或刪除具體類(lèi)都不會(huì)引起客戶(hù)端改變。

圖10:客戶(hù)端、接口、抽象工廠(chǎng)

你能否解釋清楚創(chuàng)建者模式?

創(chuàng)建者模式屬于創(chuàng)建型模式分類(lèi)。創(chuàng)建者模式幫助我們將對(duì)象的復(fù)雜構(gòu)造從其表現(xiàn)中分離開(kāi)來(lái),所以相同的構(gòu)造處理過(guò)程可以創(chuàng)建出不同的表現(xiàn)行為。當(dāng)一個(gè)對(duì)象的構(gòu)造函數(shù)非常復(fù)雜時(shí)創(chuàng)建模式非常有用;該模式主要目的就是將對(duì)象的構(gòu)造從其表現(xiàn)中分離。如果我們可以將對(duì)象的構(gòu)造與行為分離,我們就可以了從相同的構(gòu)造中獲得許多不同行為的對(duì)象。

圖11:創(chuàng)建者模式概念

為了理解我們所說(shuō)的構(gòu)造和行為,我們舉個(gè)“準(zhǔn)備茶”的例子。我們可以從圖“泡茶”中看到,從相同的泡茶步驟中我們可以得到3種不同表現(xiàn)的茶(如不含糖的茶、含糖或牛奶的茶、不含牛奶的茶)。

圖12:泡茶

現(xiàn)在讓我們來(lái)舉個(gè)軟件方面的例子來(lái)看看如何將對(duì)象復(fù)雜的創(chuàng)建和它的表現(xiàn)分開(kāi)。假設(shè)我們有一個(gè)應(yīng)用,我們需要將同一個(gè)報(bào)表顯示為pdf和excel格式。圖“請(qǐng)求報(bào)表”展示了一系列步驟來(lái)達(dá)到同一目的的流程。傳入需要?jiǎng)?chuàng)建的報(bào)表類(lèi)型、設(shè)置報(bào)表頭和腳、最終報(bào)表得以展示。

圖13:請(qǐng)求報(bào)表

接下來(lái)讓我們從下圖“不同視角”中從不同視角來(lái)再次看該問(wèn)題。圖“請(qǐng)求報(bào)表”中定義的相同流程被分解為表現(xiàn)和通用構(gòu)造。其中構(gòu)造過(guò)程對(duì)不同類(lèi)型的報(bào)表處理都是相同的,但是他們的表現(xiàn)形式卻各不相同。

還是這個(gè)報(bào)表問(wèn)題,我們嘗試使用創(chuàng)建者模式來(lái)解決該問(wèn)題。實(shí)現(xiàn)創(chuàng)建者模式分為以下3個(gè)主要部分:

Builder:主要負(fù)責(zé)定義各個(gè)部分的處理過(guò)程。Builder將各個(gè)處理過(guò)程初始化并配置到產(chǎn)品中。

Director:負(fù)責(zé)取到各個(gè)處理過(guò)程并定義構(gòu)建產(chǎn)品的流程。

Product:該對(duì)象為builder和director協(xié)作創(chuàng)建而成的最終對(duì)象。

下面讓我們來(lái)看下創(chuàng)建者模式的類(lèi)繼承關(guān)系。我們從自定義創(chuàng)建者(builder)如‘ReportPDF’、‘ReportEXCEL’中抽象出類(lèi)‘ReportBuilder’。

圖14:創(chuàng)建者類(lèi)繼承關(guān)系

下圖“創(chuàng)建者類(lèi)代碼”展示了這些類(lèi)的方法。為了生成報(bào)表我們首先需要?jiǎng)?chuàng)建一個(gè)報(bào)表對(duì)象,接下來(lái)設(shè)置報(bào)表類(lèi)型(EXCEL或者PDF)、設(shè)置表頭、設(shè)置頁(yè)腳,最終返回報(bào)表。目前我們定義了兩個(gè)自定義創(chuàng)建者,一個(gè)是‘PDF’(ReportPDF)另一個(gè)為‘EXCEL’(ReportExcel)。這兩個(gè)自定義創(chuàng)建者都根據(jù)報(bào)表類(lèi)型定義有自身的處理過(guò)程。

圖15:創(chuàng)建者代碼

接下來(lái)我們來(lái)了解director是如何工作的。‘clsDirector’持有builder并按順序調(diào)用各個(gè)方法處理。因此director就行司機(jī)一樣持有所有單個(gè)處理過(guò)程并按照一定順序來(lái)調(diào)用他們來(lái)生成最終產(chǎn)品;在這個(gè)例子中的體現(xiàn)就是報(bào)表的生成。下圖“Director實(shí)踐”展示了方法‘MakeReport’調(diào)用各個(gè)處理來(lái)生成PDF或EXCEL格式的報(bào)表。

圖16:Director實(shí)踐

創(chuàng)建者模式中第三部分組件就是產(chǎn)品(product),它在我們的例子中就僅僅是表示報(bào)表類(lèi)。

圖17:報(bào)表類(lèi)

現(xiàn)在讓我們來(lái)看一下創(chuàng)建者項(xiàng)目的完整視圖。圖“Client,builder,director以及product”展示了這些對(duì)象是如何構(gòu)成創(chuàng)建者模式的。客戶(hù)端(client)創(chuàng)建director類(lèi)對(duì)象并將恰當(dāng)?shù)膭?chuàng)建者(builder)傳遞給產(chǎn)品(product)來(lái)初始化。產(chǎn)品依賴(lài)于創(chuàng)建者被初始化或創(chuàng)建并最終傳遞給客戶(hù)端。

圖18:Client,builder,director以及product

輸出的加過(guò)就像這樣。我們可以看到兩種類(lèi)型的報(bào)表根據(jù)不同的構(gòu)建者顯示各自的報(bào)表頭。

圖19:創(chuàng)建者最終輸出結(jié)果

你能否解釋清楚原型模式?

原型模式也屬于創(chuàng)建型模式。它提供一種方式來(lái)為已經(jīng)存在的對(duì)象實(shí)例創(chuàng)建新的對(duì)象。一種方式是我們克隆已存在對(duì)象及其數(shù)據(jù);通過(guò)這種方式,對(duì)克隆對(duì)象的任何修改都不影響原對(duì)象。如果你想僅僅通過(guò)設(shè)置原對(duì)象就可以修改克隆對(duì)象,那么就錯(cuò)了。想要通過(guò)將一個(gè)對(duì)象設(shè)置到另一個(gè)對(duì)象,我們需要傳址到對(duì)象引用;因此修改新對(duì)象也會(huì)影響原對(duì)象。為了更清楚的理解傳址(“BYREF”)請(qǐng)考慮下圖“傳址”。一下是代碼流程:

第一步創(chuàng)建第一個(gè)對(duì)象,如class1的對(duì)象obj1

第二步創(chuàng)建第二個(gè)對(duì)象,如class1的對(duì)象ojb2

第三步設(shè)置舊的對(duì)象的值,如obj1設(shè)置為“old value”

第四步將obj1設(shè)置到obj2

第五步改變obj2的值

現(xiàn)在我們顯示兩個(gè)對(duì)象的值會(huì)發(fā)現(xiàn)兩個(gè)對(duì)象的值都被改變

圖20:傳址

以上例子可得出結(jié)論一個(gè)對(duì)象設(shè)置為另一個(gè)對(duì)象為傳地址。因此改變新對(duì)象值的同時(shí)也會(huì)改變?cè)瓕?duì)象的值。

然而有很多實(shí)例我們希望復(fù)制對(duì)象值的改變不影響原對(duì)象。那么最佳選擇就是原型模式。

下面我們看個(gè)c#的例子。下圖“原型模式實(shí)踐”中自定義了類(lèi)‘ClsCustomer’需要克隆。在C#中可以使用‘MemberWiseClone’方法來(lái)實(shí)現(xiàn)。Java中則可以通過(guò)‘Clone’方法來(lái)達(dá)到目的。同樣在代碼中我們還展示了客戶(hù)端代碼,我們創(chuàng)建了自定義類(lèi)的對(duì)象‘obj1’和‘obj2’。任何對(duì)obj2的改變都不會(huì)影響obj1,因?yàn)閛bj2是obj1的完全克隆復(fù)制。

圖21:原型模式實(shí)踐

你能否解釋清楚原型模式中的淺拷貝和深拷貝?

原型模式有兩種克隆方式。一種是淺拷貝,如以上例子中所示;在淺拷貝中只是拷貝對(duì)象,該對(duì)象的所包含的其他東西都不克隆;例如下圖中“深克隆實(shí)踐”我們自定義了一個(gè)類(lèi)并且在該類(lèi)中聚合了一個(gè)地址類(lèi)。‘MemberWiseClone’則只會(huì)克隆自定義類(lèi)‘ClsCustomer’而不會(huì)拷貝‘ClsAddress’類(lèi)。因此我們也為地址類(lèi)增加‘MemberWiseClone’功能。這樣當(dāng)調(diào)用‘getClone’功能時(shí)我們同時(shí)調(diào)用了父類(lèi)和子類(lèi)的克隆方法,這使得對(duì)象可以被完全拷貝。當(dāng)父類(lèi)對(duì)象和它們所包含的對(duì)象都被克隆時(shí)我們稱(chēng)之為深克隆;當(dāng)只有父類(lèi)對(duì)象被拷貝時(shí)我們稱(chēng)之為淺拷貝。

圖22:深拷貝實(shí)踐

你能否解釋清楚單例模式?

重點(diǎn):為一個(gè)對(duì)象創(chuàng)建唯一實(shí)例并通過(guò)一個(gè)統(tǒng)一的點(diǎn)來(lái)獲取該唯一實(shí)例。

在項(xiàng)目中有這樣一種場(chǎng)景,我們需要某個(gè)對(duì)象只創(chuàng)建一個(gè)實(shí)例并在客戶(hù)端之間共享。例如,假設(shè)我們有連個(gè)類(lèi)currency和country。

這些類(lèi)加載主要數(shù)據(jù)并且會(huì)被在項(xiàng)目中一次又一次被引用,但是我們想只有一個(gè)共享實(shí)例來(lái)提升性能而不是一次又一次連接查詢(xún)數(shù)據(jù)庫(kù)。

實(shí)現(xiàn)單例模式有4個(gè)步驟:

步驟1:創(chuàng)建私有構(gòu)造函數(shù)的封閉類(lèi)

私有構(gòu)造函數(shù)非常重要,因?yàn)榭蛻?hù)端不能通過(guò)該類(lèi)直接創(chuàng)建對(duì)象。本節(jié)中重點(diǎn)所示,這種模式的主要目的是為對(duì)象創(chuàng)建一個(gè)唯一的可以全局共享的實(shí)例,因此我們不希望給客戶(hù)端直接創(chuàng)建該對(duì)象的權(quán)利。

步驟2:創(chuàng)建只需要一個(gè)對(duì)象類(lèi)的對(duì)象(在這個(gè)例子中為currency和country)

步驟3:為該類(lèi)創(chuàng)建一個(gè)靜態(tài)只讀對(duì)象并同樣通過(guò)靜態(tài)屬性暴露出來(lái),如下所示:

步驟4:現(xiàn)在可以通過(guò)以下代碼在客戶(hù)端使用該單例對(duì)象

以下是我們上邊討論的單例模式完整代碼:

你能否解釋清楚命令模式?

命令模式允許請(qǐng)求以對(duì)象的方式存在。下面我們來(lái)解釋具體含義。下圖“菜單及命令”中展示了點(diǎn)擊不同菜單有不同操作的例子。因此,點(diǎn)擊不同的菜單我們傳遞一個(gè)action中所包含的字符串;通過(guò)該action字符串我們執(zhí)行不同的action。而以下代碼中不好的一點(diǎn)是其中有很多if條件語(yǔ)句使得代碼不夠清晰。

圖23:菜單及命令

命令模式將以上action移到對(duì)象中,由這些對(duì)象來(lái)執(zhí)行真正的命令。

如之前所說(shuō),每個(gè)命令是一個(gè)對(duì)象,我們首先準(zhǔn)備為每個(gè)命令準(zhǔn)備各個(gè)類(lèi),如exit,open,file以及print等。以上所有action都被包裝在類(lèi)中如退出action被包裝在‘clsExecuteExit’中,打開(kāi)被包裝在‘clsExecuteOpen’,print被包裝在‘clsExecutePrint’中等等。說(shuō)有這些類(lèi)都繼承自‘IExecute’接口。

圖24:對(duì)象及命令

我們可以創(chuàng)建inovker來(lái)使用所有action類(lèi)。invoker的主要工作就是封裝對(duì)action的調(diào)用并持有所有action類(lèi)。

這樣我們要將所有actiont添加到一個(gè)集合中如ArrayList。同時(shí)我們還開(kāi)放了一個(gè)方法‘getCommand’來(lái)接收一個(gè)字符串來(lái)返回抽象的‘IExecute’對(duì)象。到此,客戶(hù)端代碼就邊的直接而靈活了;所有的if語(yǔ)句都被移動(dòng)至‘clsInvoker’類(lèi)。

圖25:調(diào)用者及客戶(hù)端代碼

1. 本文由程序員學(xué)架構(gòu)翻譯

2. 本文譯自

http://www.codeproject.com/Articles/28309/Design-pattern-FAQ-Part-Training

3. 轉(zhuǎn)載請(qǐng)務(wù)必注明本文出自:程序員學(xué)架構(gòu)(微信號(hào):archleaner)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀(guān)點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容

  • 設(shè)計(jì)模式匯總 一、基礎(chǔ)知識(shí) 1. 設(shè)計(jì)模式概述 定義:設(shè)計(jì)模式(Design Pattern)是一套被反復(fù)使用、多...
    MinoyJet閱讀 3,970評(píng)論 1 15
  • Spring Cloud為開(kāi)發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見(jiàn)模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 134,881評(píng)論 18 139
  • 一、設(shè)計(jì)模式的分類(lèi) 總體來(lái)說(shuō)設(shè)計(jì)模式分為三大類(lèi): 創(chuàng)建型模式,共五種:工廠(chǎng)方法模式、抽象工廠(chǎng)模式、單例模式、建造者...
    RamboLI閱讀 768評(píng)論 0 1
  • 1 場(chǎng)景問(wèn)題# 1.1 選擇組裝電腦的配件## 舉個(gè)生活中常見(jiàn)的例子——組裝電腦,我們?cè)诮M裝電腦的時(shí)候,通常需要選...
    七寸知架構(gòu)閱讀 4,410評(píng)論 6 67
  • 1 場(chǎng)景問(wèn)題# 大家都知道,在Java應(yīng)用開(kāi)發(fā)中,要“面向接口編程”。那么什么是接口?接口有什么作用?接口如何使用...
    七寸知架構(gòu)閱讀 6,488評(píng)論 14 70