天天看點

設計模式之死磕工廠方法模式(原創)

在 

設計模式之工廠模式

 中,我們提到過工廠模式仔細區分的話分為三種,分别是簡單工廠模式、工廠方法模式以及抽象工廠模式。在上面已經介紹完畢了工廠模式(也就是簡單工廠模式)。本篇文章主要學習的是工廠模式的第二種,工廠方法模式。

注:本文是基于 

 的文章之上進行編碼以及項目說明

首先回顧下工廠模式的基本概念:我們在建立對象時不會對用戶端直接暴露建立邏輯,而是 通過使用一個共同的接口根據不同的條件來指向具體想要建立的對象。

通過一個共同的接口根據不同的條件來指向想要建立的對象,這個切入點肯定沒錯,在上一篇文章也講到,我們通過使用工廠模式的優點在于一個調用者想建立一個對象,隻要知道其名稱(也就是不同的标簽)就可以在工廠擷取具體的對象;其次,在這種設計模式下會屏蔽産品的具體實作,調用者隻關心産品的接口、無需關心内部實作。

但是,這樣也會帶來一個問題,

如果我想增加一個(也就是具體的對象),那就需要擴充工廠類

(也就是首先要增加不同的标簽,然後增加不同标簽所對應的對象)。如果這樣操作的話,就違背了“開閉”原則。那麼,什麼是開閉原則?

設計模式概念與簡介

 這篇文章中簡單介紹了開閉原則,那麼這裡對開閉原則做更加詳細的分析。

開閉原則(OCP)是面向對象設計中“可複用設計”的基石,是面向對象設計中最重要的原則之一,其它很多的設計原則都是實作開閉原則的一種手段。開、閉的字面了解就是

對于擴充是開放的,對于修改是關閉的

,這意味着子產品的行為是可以擴充的。當應用的需求改變時,我們可以對子產品進行擴充,使其具有滿足那些改變的新行為。更通俗一點,也就是:軟體系統中包含的各種元件,例如子產品(Modules)、類(Classes)以及功能(Functions)等等,應該在不修改現有代碼的基礎上,引入新功能。

既然開閉原則是如此的重要,那麼開發者應該

如何實作開閉原則

A:抽象限制 

抽象是對一組事物的通用描述,沒有具體的實作,也就表示它可以有非常多的可能性,可以跟随需求的變化而變化。是以,通過接口或抽象類可以限制一組可能變化的行為,并且能夠實作對擴充開放,其包含三層含義:

通過接口或抽象類限制擴散,對擴充進行邊界限定,不允許出現在接口或抽象類中不存在的public方法。

參數類型,引用對象盡量使用接口或抽象類,而不是實作類,這主要是實作裡氏替換原則的一個要求

抽象層盡量保持穩定,一旦确定就不要修改

B:中繼資料(metadata)控件子產品行為 

程式設計是一個很苦很累的活,那怎麼才能減輕壓力呢?答案是盡量使用中繼資料來控制程式的行為,減少重複開發。什麼是中繼資料?用來描述環境和資料的資料,通俗的說就是配置參數,參數可以從檔案中獲得,也可以從資料庫中獲得。

C:制定項目章程 

在一個團隊中,建立項目章程是非常重要的,因為章程是所有人員都必須遵守的約定,對項目來說,約定優于配置。這比通過接口或抽象類進行限制效率更高,而擴充性一點也沒有減少。

D:封裝變化 

對變化封裝包含兩層含義: 

(1)将相同的變化封裝到一個接口或抽象類中 

(2)将不同的變化封裝到不同的接口或抽象類中,不應該有兩個不同的變化出現在同一個接口或抽象類中。 

封裝變化,也就是受保護的變化,找出預計有變化或不穩定的點,我們為這些變化點建立穩定的接口。

開閉原則的具體實作與互相關系:

開閉原則被稱作面向對象設計的終極目标。是以,針對開閉原則的實作方法,一直都有面向對象設計的大師費盡心機去研究開閉原則的實作方式。但是在平時的開發中我們已經直接或者間接的已經接觸到了開閉原則的設計理念。比如,設計模式概念中提到的裡氏代換原則、依賴倒轉原則、接口隔離原則 以及常用的接口、抽象類等等,都可以看作是開閉原則的具體實作方法。

那麼在回到上面的問題,當需求發生變化的時候,簡單工廠模式下進行修改操作的話是違背開閉原則的(當然你說這樣也無所謂,這個功能怎麼實作我不管、反正可以用就行),那麼如何解決上面的問題?

比較高效和容易了解的方式是,在定義一個抽象的英雄工廠類型的基類,讓子類自己去實作該基類(也就是工廠與執行個體對象互相對應)。

首先還是跟上一篇文章一樣,基本代碼不變:

設計模式之死磕工廠方法模式(原創)

英雄規範

接着是已持有的三個英雄:

設計模式之死磕工廠方法模式(原創)

Ashe

設計模式之死磕工廠方法模式(原創)

MasterYi

設計模式之死磕工廠方法模式(原創)

Timor

上面的代碼和簡單工廠模式下的代碼都是一樣的,針對上面的問題,我們提到可以定義一個抽象的英雄工廠類型的基類

設計模式之死磕工廠方法模式(原創)

定義基類

其中,這裡基類的抽象方法,傳回的是具體的英雄參數類型,那麼通過子類就可以進行具體的操作(将對象傳回出去即可)三個具體的英雄對應三種具體的工廠

設計模式之死磕工廠方法模式(原創)

射手工廠

設計模式之死磕工廠方法模式(原創)

法師工廠

設計模式之死磕工廠方法模式(原創)

戰士工廠

定義完三個工廠以後,我們就可以測試使用了:

設計模式之死磕工廠方法模式(原創)

測試工廠方法模式

可能會說,這兩種模式有什麼差別?這裡先上一下兩種工廠模式下的測試類比較:

設計模式之死磕工廠方法模式(原創)

兩種模式測試比較

其中,紅色箭頭的是簡單工廠模式(這種模式下将所有的标簽和對象全部統一在這裡進行管理使用)

藍色箭頭代表的是工廠方法模式,在這種模式下,各個工廠内對象依據工廠類型不同進行建立。

簡單工廠模式和工廠方法模式的比較:

簡單工廠模式是專門定義一個類(工廠類)來負責建立其他類的執行個體,被建立的執行個體通常都具有共同的父類。它又稱為靜态工廠方法模式。本質是由一個工廠類根據傳入的參數動态決定建立那一個産品類(這些産品類繼承自一個父類或接口)的執行個體對象。在這種模式下工廠類是整個模式的關鍵,它包含必要的邏輯判斷能夠根據外界給定的資訊決定究竟應該建立那個具體類的對象。

工廠方法模式是粒度很小的設計模式,因為模式的表現是一個抽象的方法。提前定義用于建立對象的接口讓子類決定執行個體化具體的某一個類,即在工廠和産品中間增加一個接口(或者抽象類),工廠不再負責産品的建立,由接口針對不同條件傳回具體的執行個體,由具體類執行個體去實作。工廠方法模式是簡單工廠模式的衍生解決了之前簡單工廠模式下帶來的問題。完全實作了開閉原則。工廠方法模式是對簡單工廠模式進行了抽象。有一個抽象的Factory類(接口或者抽象)這個類不在負責具體的産品生産(也就是new 對象),而是隻指定規範,具體的實作由子類完成。在這種模式下,工廠類和産品往往可以互相對應。即一個抽象工廠對應一個抽象産品,一個具體的工廠對應一個具體的産品,這個具體的工廠就負責生産對象的産品(也就是上面的藍色箭頭)

簡單工廠模式和工廠方法模式的優缺點:

簡單工廠模式:

優點:工廠類含有必要的邏輯判斷,可以依據不同的标簽建立不同的對象,實作了對責任的分割,耦合性較低。有利于整個軟體體系結構的優化

缺點:拓展性相對較低(是以出現了工廠方法模式)

工廠方法模式:

優點:這種模式是為了克服簡單工廠模式下的缺點(主要是開閉原則),這種模式下每個具體的工廠類隻完成單一任務,代碼簡潔,拓展性強

缺點:不易于維護,修改産品對象也要修改對應的工廠類(修改多個産品就要修改多個工廠)

簡單工廠模式和工廠方法模式的适用範圍:

簡單工廠模式:工廠類負責建立的對象比較少,客戶隻知道傳入了工廠類的參數,對于建立的邏輯不關心。且使用一個共同的接口根據不同的條件來指向具體想要建立的對象可以使用簡單工廠模式

工廠方法模式:當一個類不知道它所必須建立對象的類或者一個類希望由子類來指定它所建立的對象時;當類将建立的需的職責委托給幫助類中的某一個,并且希望得到指定幫助類的資訊,可以使用工廠方法模式

參考資料:百度百科

如果這篇文章對你有幫助,希望各位看官留下寶貴的star,謝謝。

Ps:著作權歸作者所有,轉載請注明作者, 商業轉載請聯系作者獲得授權,非商業轉載請注明出處(開頭或結尾請添加轉載出處,添加原文url位址),文章請勿濫用,也希望大家尊重筆者的勞動成果。