1. 程式人生 > 實用技巧 >第1部分設計模式FAQ(培訓)

第1部分設計模式FAQ(培訓)

用Singleton模式的解釋進行了更新。 設計模式常見問題解答 什麼是設計模式? 你能解釋一下工廠模式嗎? 你能解釋一下抽象工廠模式嗎? 你能解釋一下構建器模式嗎? 你能解釋一下原型圖案嗎? 你能解釋一下原型模式中的淺拷貝和深拷貝嗎? 你能解釋一下單例模式嗎? 你能解釋一下命令模式嗎? 一個專案的設計模式 介紹 這裡有一個關於設計模式的問答和格式。在本節中,我們將討論工廠、抽象工廠、構建器、原型、淺原型和深原型、單例模式和命令模式。 , 你可以閱讀我的其他設計模式FAQ部分相同在下面的連結:- 第2部分設計模式FAQ—直譯器模式、迭代器模式、中介器模式、記憶器模式和觀察者模式 第三部分FAQ的設計模式——狀態模式、策略模式、訪問者模式、介面卡模式和飛重模式 第4部分設計模式FAQ—橋式模式、複合模式、裝飾模式、Facade模式、責任鏈(COR)、代理模式和模板模式 什麼是設計模式? 設計模式是為在給定上下文中重複出現的問題編制的經過試驗和測試的解決方案。所以基本上你有了問題背景和建議的解決方案。設計模式在軟體開發的初始階段就以某種或其他形式存在。假設你想實現一種排序演算法首先想到的是氣泡排序。問題是排序,解決方法是氣泡排序。設計模式也是如此。 哪三種主要的設計模式? 模式有三種基本分類:建立模式、結構模式和行為模式。 建立型模式 •抽象工廠:-建立多個類家族的例項 •Builder: -將物件構造與表示分離 •工廠方法:——建立多個派生類的例項 •Prototype:-一個完全初始化的要複製或克隆的例項 •Singleton:一個類中只能存在一個例項 注意:-記住創造模式的最好方法是記住ABFPS(亞伯拉罕成為第一任總統)。 結構模式 •介面卡:-匹配不同類的介面。 橋:-將物件的抽象與實現分離。 複合:一個由簡單物件和複合物件組成的樹形結構。 •Decorator:-動態地向物件新增責任。 外觀:表示整個子系統的單個類。 -一個用於高效共享的細粒度例項。 代理:一個代表另一個物件的物件。 中介:-定義類之間簡化的通訊。 •紀念品:-捕獲並恢復物件的內部狀態。 在程式中包含語言元素的一種方法。 •迭代器:-按順序訪問集合中的元素。 •Resp鏈:-在物件鏈之間傳遞請求的方法。 •Command:-將命令請求封裝為物件。 狀態:-當一個物件的狀態改變時改變它的行為。 •策略:-將演算法封裝在類中。 觀察者:-一種通知一些類的變化的方式。 •模板方法:-將演算法的具體步驟延遲到子類。 訪問者:-定義一個新的操作到一個類沒有改變。 你能解釋一下工廠模式嗎? 工廠模式是建立模式的一種型別。你可以從工廠這個名字本身看出它的意思是要建造和創造一些東西。在軟體架構中,世界工廠模式意味著集中建立物件。下面是一個客戶機的程式碼片段,它有不同型別的發票。這些發票根據客戶指定的發票型別建立。以下程式碼有兩個問題:- 首先,我們有很多'新的'關鍵字分散在客戶端。在其他方面,客戶端裝載了大量的物件建立活動,這可能使客戶端邏輯非常複雜。 第二個問題是客戶需要了解所有型別的發票。因此,如果我們要新增一個名為“InvoiceWithFooter”的發票類型別,我們需要在客戶端中引用這個新類並重新編譯客戶端。 圖:-不同型別的發票 以這些問題為基礎,我們現在來看看工廠模式如何幫助我們解決同樣的問題。下圖“工廠模式”顯示了兩個具體的類“ClsInvoiceWithHeader”和“ClsInvoiceWithOutHeader”。 第一個問題是,這些類與客戶端直接接觸,這導致很多“新”關鍵字分散在客戶端程式碼。通過引入一個新類' ClsFactoryInvoice '來消除這個問題,這個類負責建立所有的物件。 第二個問題是客戶端程式碼同時知道具體的類,例如“ClsInvoiceWithHeader”和“ClsInvoiceWithOutHeader”。這導致重新編譯新增新發票型別時的客戶端程式碼。例如,如果我們添加了‘ClsInvoiceWithFooter’,客戶端程式碼需要相應地進行更改和重新編譯。為了解決這個問題,我們引入了一個通用介面' IInvoice '。具體類' ClsInvoiceWithHeader '和' ClsInvoiceWithOutHeader '繼承並實現' IInvoice '介面。 客戶端僅引用' IInvoice '介面,這導致客戶端和具體類之間的零連線(' ClsInvoiceWithHeader '和' ClsInvoiceWithOutHeader ')。所以現在如果我們新增新的具體的invoice類,我們不需要在客戶端更改任何東西。 在一行中,物件的建立由' ClsFactoryInvoice '負責,客戶端與具體類的斷開由' IInvoice '介面負責。 圖:-工廠模式 下面是如何在c#中實現工廠模式的程式碼片段。為了避免重新編譯客戶端,我們引入了invoice介面' IInvoice '。具體類“ClsInvoiceWithOutHeaders”和“ClsInvoiceWithHeader”都繼承並實現了“IInvoice”介面。 圖:-介面和具體類 我們還引入了一個額外的類' ClsFactoryInvoice ',帶有一個函式' getInvoice() ',它將根據' intInvoiceType '的值生成兩個發票的物件。簡而言之,我們將物件建立的邏輯集中在“ClsFactoryInvoice”中。客戶端呼叫' getInvoice '函式來生成發票類。需要注意的最重要的一點是,客戶端僅引用“IInvoice”型別,而工廠類“ClsFactoryInvoice”也提供了相同型別的引用。這有助於客戶端與具體類完全分離,因此現在當我們新增新類和發票型別時,我們不需要重新編譯客戶端。 圖:-生成物件的工廠類 你能解釋一下抽象工廠模式嗎? 抽象工廠是對基本工廠模式的擴充套件。抽象工廠幫助我們將類似的工廠模式類統一到一個統一的介面中。因此,基本上所有公共工廠模式現在都繼承了一個公共抽象工廠類,該類將它們統一在一個公共類中。與工廠模式相關的所有其他內容與上一個問題中討論的內容相同。 工廠類幫助我們集中建立類和型別。抽象工廠可以使相關的工廠模式保持一致,從而使客戶端介面更加簡化。 圖:-抽象工廠統一了相關的工廠模式 現在我們已經瞭解了基本的知識,讓我們來嘗試理解抽象工廠模式是如何實際實現的細節。如前所述,我們通過繼承將工廠模式類(factory1和factory2)繫結到一個公共抽象工廠(AbstractFactory介面)。工廠類位於具體類的頂部,這些類同樣派生自公共介面。例如,在圖“抽象工廠的實現”中,具體類“product1”和“product2”都繼承了一個介面,即“common”。想要使用具體類的客戶端將只與抽象工廠和具體類繼承的公共介面互動。 圖:抽象工廠的實現 現在讓我們看看如何在實際程式碼中實際實現抽象工廠。我們有這樣的場景,我們有UI建立活動的文字框和按鈕通過他們自己的集中工廠類' ClsFactoryButton '和' ClsFactoryText '。這兩個類都繼承了通用介面“InterfaceRender”。工廠的' ClsFactoryButton '和' ClsFactoryText '都繼承了公共工廠' ClsAbstractFactory '。圖“AbstractFactory的示例”顯示了這些類是如何安排的以及它們的客戶端程式碼。關於客戶端程式碼,需要注意的重要一點是它不與具體類互動。為了建立物件,它使用抽象工廠(ClsAbstractFactory),為了呼叫具體類實現,它通過介面“InterfaceRender”呼叫方法。因此' ClsAbstractFactory '類為兩個工廠' ClsFactoryButton '和' ClsFactoryText '提供了一個公共介面。 圖:-以抽象工廠為例 我們將執行抽象工廠的示例程式碼。下面的程式碼片段“抽象工廠和工廠程式碼片段”展示了工廠模式類如何從抽象工廠繼承。 圖:-抽象工廠和工廠程式碼片段 圖“具體類的公共介面”具體類如何繼承公共介面“InterFaceRender”,該介面在所有具體類中強制執行方法“render”。 圖:-具體類的公共介面 最後是客戶端程式碼,它使用介面“InterfaceRender”和抽象工廠“ClsAbstractFactory”來呼叫和建立物件關於該程式碼的重要一點是,它與具體類完全隔離。因此,任何具體類中的更改(如新增和刪除具體類)都不需要客戶端級別的更改。 圖:-客戶端、介面和抽象工廠 你能解釋一下構建器模式嗎? 生成器屬於建立模式類別的型別。Builder模式幫助我們將複雜物件的構造與其表示分離開來,以便相同的構造過程可以建立不同的表示。當物件的構造非常複雜時,構建器模式非常有用。主要目的是分離物件的構造和它們的表徵。如果我們能夠分離結構和表徵,我們就可以從同一結構中得到許多表徵。 圖:-建設者的概念 為了理解我們所說的構造和表示是什麼意思,讓我們以下面的“沏茶”序列為例。 從圖中可以看出,通過同樣的沏茶步驟,我們可以得到三種茶的表現形式(即不加糖的茶、加糖/牛奶的茶和不加牛奶的茶)。 圖:-準備茶 現在讓我們以軟體世界中的一個實時示例來看看builder是如何分離複雜的建立和表示的。考慮我們有一個應用程式,我們需要同樣的報告顯示為' PDF '或' EXCEL '格式。圖“請求報告”顯示了實現此目標的一系列步驟。根據報表型別,建立一個新報表,設定報表型別,設定報表的頁首和頁尾,最後我們得到要顯示的報表。 圖:-請求報告 現在讓我們從不同的角度來看待這個問題,如圖“不同的觀點”所示。在“請求報告”中定義的相同流現在以表示和常見結構進行分析。這兩種型別的報告的構建過程是相同的,但是它們會導致不同的表示。 圖:-不同的觀點 我們將使用相同的報表問題,並嘗試使用構建器模式來解決相同的問題。當您想要實現構建器模式時,有三個主要部分。 •建造者:建造者負責定義單個零件的建造過程。構建器有那些單獨的流程來初始化和配置產品。 Director: - Director從構建者那裡獲取這些單獨的流程,並定義構建產品的順序。 •產品:-產品是由建造者和總監協調生產的最終物件。 首先讓我們看一下構建器類的層次結構。我們有一個名為“ReportBuilder”的抽象類,將從它生成自定義生成器,如“ReportPDF”生成器和“ReportEXCEL”生成器。 圖:-構建器類層次結構 圖“實際程式碼中的構建器類”顯示了類的方法。要生成報表,我們需要首先建立一個新報表,設定報表型別(EXCEL或PDF),設定報表標題,設定報表頁尾,最後獲得報表。我們已經定義了兩個自定義構建器,一個用於“PDF”(ReportPDF),另一個用於“EXCEL”(ReportExcel)。這兩個自定義構建器根據報表型別在那裡定義自己的流程。 圖:-實際程式碼中的生成器類 現在讓我們瞭解一下director是如何工作的。類' clsDirector '接受構建器並按順序呼叫單個方法流程。因此,director就像一個驅動程式,它獲取所有單獨的程序,並按順序呼叫它們以生成最終產品,在本例中就是報告。圖“Director in action”顯示了方法“MakeReport”如何呼叫單個流程,以通過PDF或EXCEL生成報告產品。 圖:-導演在行動 構建器中的第三個元件是產品,在本例中它就是報表類。 圖:-報告類 現在讓我們看一下builder專案的俯檢視。圖“客戶、建設者、總監和產品”展示了他們是如何實現建設者模式的。客戶端建立director類的物件,並傳遞適當的構建器來初始化產品。根據構建器的不同,產品會被初始化/建立並最終傳送到客戶端。 圖:-客戶,建造商,總監和產品 輸出是這樣的。我們可以看到根據構建器顯示兩種報表型別及其標題。 圖:-建造器的最終輸出 你能解釋一下原型圖案嗎? 原型模式屬於建立模式的一部分。它為我們提供了一種從物件的現有例項建立新物件的方法。在一句話中,我們克隆了現有物件及其資料。通過克隆對克隆物件的任何更改都不會影響原始物件值。如果你認為通過設定物件我們可以得到一個克隆,那麼你就錯了。通過將一個物件設定為另一個物件,我們設定了物件BYREF的引用。所以陳隊的新物件也改變了原來的物件。時瞭解BYREF基本更清楚地考慮下面的圖時的BYREF”。下面是以下的順序程式碼: 在第一步,我們已經建立了第一個物件即其中obj1 class1。在第二步中,我們建立了第二個物體即methoda class1。在第三步我們將舊的值物件即其中obj1舊值。在第四步中我們設定了其中obj1 methoda。我們在第五步改變methoda值。現在我們顯示的值,我們發現物件的新值。 圖:時,BYREf 上面的例子中得出的結論是,當設定為其他物件時設定BYREF物件。所以新物件值變化也改變了舊物件值。 有許多情況下,我們希望新副本物件變化不應該影響到舊的物件。這個問題的答案是原型模式。 讓看我們如何使用c#實現相同的。在下面圖“原型在行動”我們客戶類的ClsCustomer需要克隆。這可以在c#中使用“MemberWiseClone”方法。在JAVA中我們有“克隆”的方法來達到相同的。在相同的程式碼我們還展示了客戶端程式碼。我們已經建立了兩個物件的客戶類“其中obj1”和“methoda”。任何更改的methoda不會影響“其中obj1”,因為它是一個完整的克隆複製。 圖:原型 你能解釋一下淺拷貝和深拷貝在原型模式? 有兩種型別的克隆為原型模式。一個是淺克隆你剛剛讀的第一個問題。只在淺拷貝物件克隆,任何物件包含的物件不是克隆。例如考慮圖“深克隆在行動”我們有一個客戶類和我們有一個地址類聚合內部客戶類。“MemberWiseClone”只會克隆customer類“ClsCustomer”而不是“ClsAddress”類。所以我們增加了MemberWiseClone address類的函式也。現在,當我們呼叫getClone的函式呼叫父克隆函式和還孩子克隆功能,導致克隆完整的物件。當父物件克隆與包含物件稱為深克隆,當只有父母是克隆其稱為淺克隆。 圖:-深克隆 你能解釋單例模式嗎? 隱藏,複製Code

Punch :-  Create a single instance of object and provides access to this single instance via a central point.

情況在專案中,我們希望只有一個例項物件的建立和共享之間的客戶。例如假設有以下兩個類,貨幣和國家。 這些類載入主資料將會被一次又一次的專案。我們想分享類的一個例項獲得性能優勢不觸及資料庫一次又一次。 隱藏,複製Code

public class Currency
    {
        List<string> oCurrencies = new List<string>();
        public Currency()
        {
            oCurrencies.Add("INR");
            oCurrencies.Add("USD");
            oCurrencies.Add("NEP");
            oCurrencies.Add("GBP");

        }
        public IEnumerable<string> getCurrencies()
        {
            return (IEnumerable<string>)oCurrencies;
        }
    }
</string></string></string></string>

隱藏,複製Code

public class Country
    {
        List<string> oCountries = new List<string>();
        public Country()
        {
            oCountries.Add("India");
            oCountries.Add("Nepal");
            oCountries.Add("USA");
            oCountries.Add("UK");

        }
        public IEnumerable<string> getCounties()
        {
            return (IEnumerable<string>) oCountries;
        }
    }
</string></string></string></string>

實現單例模式是一個4步驟的過程。 步驟1:建立一個密封類私有建構函式 私有建構函式是非常重要的,這樣客戶不能直接建立物件的類。如果你還記得,這一模式的主要目的是建立一個單一例項的物件可以共享在全球範圍內,所以我們不想給客戶直接控制建立例項。 隱藏,複製Code

public sealed class GlobalSingleton
    {
private GlobalSingleton() { }

	………..
	……….
	}

步驟2:建立聚合物件的類(在本例中它是貨幣和國家),我們希望單一例項。 隱藏,複製Code

public sealed class GlobalSingleton
    {
        // object which needs to be shared globally
        public Currency Currencies = new Currency();
        public Country Countries = new Country();

步驟3:建立一個靜態只讀物件t他類本身,讓同樣的通過靜態屬性,如下所示。 隱藏,複製Code

public sealed class GlobalSingleton
    {
	….
	…
// use static variable to create a single instance of the object
static readonly GlobalSingleton INSTANCE = new GlobalSingleton();

public static GlobalSingleton Instance
        {
            get
            {
              
                return INSTANCE;
            }
        }       
    }

步驟4:現在你可以使用單例物件從客戶機使用以下程式碼。 隱藏,複製Code

GlobalSingleton oSingle = GlobalSingleton.Instance;
Country o = osingl1.Country;

下面是單例模式的完整程式碼,我們上面所討論的。 隱藏,複製Code

public sealed class GlobalSingleton
    {
        // object which needs to be shared globally
        public Currency Currencies = new Currency();
        public Country Countries = new Country();

        // use static variable to create a single instance of the object
        static readonly GlobalSingleton INSTANCE = new GlobalSingleton();

        /// This is a private constructor, meaning no outsides have access.
        private GlobalSingleton() 
        { }
        
public static GlobalSingleton Instance
        {
            get
            {
              
                return INSTANCE;
            }
        }       
    }

你能解釋命令模式嗎? 命令模式允許請求作為一個物件存在。好讓我們理解這意味著什麼。考慮圖的選單和命令我們有不同的行為根據選單點選。所以這取決於選單點選我們傳遞一個字串,將行動行動中的文字字串。根據字串的操作我們將執行行動。壞的程式碼是它有很多‘如果’條件使編碼更神祕。 圖:選單和命令 命令模式將上述行動物件。實際上這些物件執行時執行命令。 正如前面說的每一個命令是一個物件。我們首先為每個動作準備單獨的類即退出,開放,檔案和列印。Al l以上行為是封裝在類像退出行動是包裹在“clsExecuteExit”,開放的行動是包裹在“clsExecuteOpen”,列印操作是包裹在“clsExecutePrint”等等。所有這些類都繼承自一個公共介面“IExecute”。圖:物件和命令 使用所有action類我們可以呼叫程式。呼叫程式的主要工作是地圖的動作類的行動。 所以我們增加了一個集合中的所有行為即arraylist。我們暴露“getCommand”方法接受一個字串和回饋抽象物件“IExecute”。現在客戶端程式碼整潔乾淨。所有的“如果”條件現在搬到“clsInvoker”類。 圖:客戶機呼叫者和清潔 以防你的全新設計模式或你真的不想讀這個complete文章確實看到我們的免費設計pattern培訓和麵試問題/答案視訊。 下面是一個很好的設計模式youtube視訊一步一步這解釋瞭如何使用設計模式在c#專案。 設計模式的一個專案 學習設計模式的最好方法是通過做一個專案。本教程教你模式的模式但如果你想使用一個專案學習設計模式的方法,點選這個連結。 本文轉載於:http://www.diyabc.com/frontweb/news2068.html