HeadFirst 設計模式學習筆記4 工廠模式

2021-08-26 10:31:48 字數 4917 閱讀 8547

1.我們在前邊提到乙個原則就是「面向介面而不要面向實現程式設計」,但是我們一直在使用duck duck = new mallardduck()這樣的模式,後邊的new語句卻違反了這個原則。工廠方法就可以解決這個問題,它用來封裝物件的建立。

2.這一節我們考慮如下場景:乙個披薩店要製作各種各樣的披薩,甚至還要開分店。其中涉及到訂購披薩的步驟。我們可以把orderpizza中的關於製作pizza的部分單獨提取到乙個類中。

public class pizzastore

public pizza orderpizza(string type)

}而製作pizza的類如下,這是乙個簡單工廠方法:

public class ******pizzafactory else if (type.equals("pepperoni")) else if (type.equals("clam")) else if (type.equals("veggie"))

return pizza;}}

這樣,乙個pizza商店在製作pizza時等於有了乙個**商一樣的東西專門去製作,而商店不必要去關心這些的細節。這本來是可以再orderpizza中實現的,現在單獨形成類時為了可以服務更多的商店(比如同時經營的連鎖店)或者不同的吃法(比如送貨上門)。這樣的實現稱為簡單工廠模式,也可以使用靜態方法來定義者這個工廠方法,當然這樣的實現有個缺點就是無法通過繼承改變建立方法的行為。注意,簡單工廠模式並不等價於工廠模式。

3.工廠方法:現在我們考慮更多加盟店的需求:他們需要他們自己風格的口味,但是加盟店的一些業務流程又必須嚴格按照總店進行處理。

針對這樣的需求,我們重新設計pizzastore類,將createpizza方法從******pizzafactory 中移出來,設定為抽象的——加盟店必須自己完成這個方法自定義他們的pizza,而orderpizza就保證了流程都是一樣的,要是擔心新的加盟店在繼承後通過覆蓋而改動這個方法則可以在前邊加上final:

publicabstractclass pizzastore

}此時,我們開一家芝加哥的分店:

public class chicagopizzastoreextends pizzastore else if (item.equals("veggie")) else if (item.equals("clam")) else if (item.equals("pepperoni")) else return null;}}

我們然後實現pizza本身的一些事情:

publicabstractclass pizza

}void bake()

void cut()

void box()

public string getname()

根據總店的規定,我們來自定義乙個芝加哥風味的pizza:

public class chicagostyleclampizzaextends pizza

void cut()

}ok,all done,我們可以去吃一頓披薩大餐了:

public class pizzatestdrive

}4.工廠方法模式的定義:定義了乙個建立物件的介面(abstract createpizza),但由子類決定要例項化的類是哪乙個。工廠方法讓類把例項化推遲到子類。優點在於將建立物件的**集中在乙個類或者方法中,可以避免**中的重複,並且方便以後的管理,並且客戶在例項化物件時只會依賴於介面而不是具體的類。在**中使用new建立其他的類就是對其他類的依賴,減少對於具體類的依賴是件好事情,這就引出我們第六個設計原則:要依賴抽象,不要依賴具體類——這有點類似於我們第乙個原則,但是這裡更強調不能讓高層元件依賴低層元件,而且,兩者都應該依賴於抽象。在這個例子中,***pizza --> pizza <- pizzastore,而pizza則是乙個抽象類,這就是well designed.思維的方式是逆向思維,在設計系統時,先從底部向上抽象(抽象出pizza類),然後撇開具體的類,在抽象層面拓展(設計pizzastore),有幾個原則可以幫助我們規範使用這個原則,這些並不是都要做到,只要盡力即可:

5.抽象工廠模式:

我們現在的場景是要在pizza上採用不同的原料,針對不同的分店,首先我們先定義乙個產生原料的工廠(抽象工廠類),我們有六種原料要**:

public inte***cepizzaingredientfactory

(注:如果每個具體工廠類內部需要實現某種通用機制,這裡就採用抽象類)

我們根據這一模式構建各地的分工廠(具體工廠類):

public class nypizzaingredientfactory implements pizzaingredientfactory

public sauce createsauce()

public cheese createcheese()

public veggies createveggies()

veggies veggies = ;

return veggies;

}public pepperoni createpepperoni()

public clams createclam()

}現在我們就做乙個pizza,使用原料工廠提供的原料,這是乙個抽象產品類:

public abstract class pizza

void cut()

void box()

void setname(string name)

string getname()

public string tostring()

}針對這乙個基本的方式,我們構建具體的pizza(這是具體產品類):

public class cheesepizza extends pizza

void prepare()

}接著,我們要在店面上進行抽象(抽象工廠類):

public abstract class pizzastore

}在這個抽象的基礎上我們開一家分店(具體工廠類):

public class nypizzastore extends pizzastore else if (item.equals("veggie")) else if (item.equals("clam")) else if (item.equals("pepperoni"))

return pizza;}}

現在我們試著訂購乙個pizza:

public class pizzatestdrive

}抽象工廠方法提供了乙個介面(此例中為pizzaingredientfactory),用於建立相關或者依賴的物件家族,而不需要明確指定具體類,每個家族成員(此例為nypizzaingredientfactory)都負責建立乙個具體的產品。與工廠方法的區別在於:工廠方法使用繼承,針對的是類,利用工廠方法建立物件要擴充套件乙個類,並覆蓋它的工廠方法(例如這裡的createpizza)——用來建立物件,工廠方法的實質在於通過子類建立物件;抽象工廠方法使用的是組合(ingredientfactory),針對的是一族物件,要使用這個工廠要首先將其實例化,然後將它傳入一些針對抽象型別所寫的**中,優點在於可以把一群相關的產品集合起來,具體的工廠都是由工廠方法(prepare)建立的(這就是工廠方法和抽象工廠方法的聯絡)。在這個例子中商店的實現是採用的工廠方法,而製作pizza的原料相關的類是採用的抽象工廠方法。

總結起來,這三者如下:

*************************=

簡單工廠方法中,

首先包括乙個「抽象產品類」(該類可以是介面inte***ce,也可以是實際的類class,本例中是pizza),所有需要的產品類都是該「抽象產品類」的子類(如果是介面的話,那麼就是說所有產品類都繼承了該介面),本例中為各種xxpizza。

另外還包含乙個具體的工廠類(本例為******pizzafactory),所有需要的產品類都是該類生成的產品類物件。生成產品類的方法,其內部一般是類似於switch的結構,根據輸入的標誌,選擇建立不同型別的物件。由於不知道建立的物件到底是哪個類的,所以方法的返回值的型別是「抽象產品類」。譬如,pizza createpizza(string type),type就是乙個標誌,返回的是pizza這個抽象產品類。

*************************=

工廠方法中,

首先包括乙個抽象產品類(本例中是pizza),可以派生出多個具體產品類(本例為***pizza),這個和簡單工廠方法沒有區別。

另外還包含乙個抽象工廠類(本例為pizzastore),可以派生出具體工廠類(本例為***pizzastore,這個與簡單工廠方法中的具體工廠類沒有區別), 每個具體工廠類(比如本例的chicagopizzastore )可以根據輸入標誌建立乙個具體產品類的例項。

較之簡單工廠方法,工廠方法對於工廠類進行了抽象產生了乙個抽象工廠類,通過這個抽象工廠類規定了一系列流程框架(orderpizza方法),另外,還將具體產品類的建立交給了具體的工廠類(createpizza在***pizza類中的實現)——也就是說,有多個具體工廠類相對應多個具體產品類,工廠類和產品類的耦合度下降。在本例中,如果不使用工廠方法,那麼createpizza除了傳入pizza的型別還要傳入商店的地點資訊,譬如chicago,這樣的耦合度就會很大。

*************************=

抽象工廠方法中,

首先,包括乙個抽個產品類(本例中為pizza),該抽象產品類可以派生出多個具體產品類(本例為***pizza),在每個具體產品類中以組合的形式將另乙個抽象工廠類(本例為pizzaingredientfactory )的引用包含進來,完成一群具體產品類的構建(***pizza的prepare方法)。

另外還包含兩個抽象工廠類,本例中pizzastore,可以派生出多個具體工廠類***pizzastore,這個與簡單工廠方法中的具體工廠類沒有區別,每個具體工廠類可以建立乙個具體產品類的例項(***pizza),但是這個具體產品類的例項比較特殊,是利用另乙個抽象工廠類pizzaingredientfactory 的具體工廠類建立的一群具體產品類而構建(***pizza的prepare方法),請注意這個類才是抽象工廠方法的實質。

《Head first設計模式》學習筆記

開閉原則的意思是 對擴充套件開放,對修改關閉。在程式需要進行拓展的時候,不能去修改原有的 實現乙個熱插拔的效果。簡言之,是為了使程式的擴充套件性好,易於維護和公升級。想要達到這樣的效果,我們需要使用介面和抽象類,後面的具體設計中我們會提到這點。黎克特制代換原則是物件導向設計的基本原則之一。黎克特制代...

headfirst設計模式

花了一周多一點的時間看完了headfirst的設計模式。看完之後有一種恍然大悟的感覺,仔細想想有覺得自己好像什麼也看懂。簡單說下對這本書的一點感悟吧,headfirst的書比較通俗易懂,之前看了四人幫的設計模式,看一半就有一種痛不欲生的感覺,自己水平有限,看不懂,也就沒在勉強自己了。對於模式其實簡單...

HeadFirst設計模式學習筆記02

執行時擴充套件,遠比編譯時繼承威力大。熟悉了裝飾的技巧,能夠在不改變任何底層 的情況下,給你的物件賦予新的職責。星巴茲starbuzz以擴張速度快聞名,準備更新訂單系統,以適應他們的飲料 要求。原先類的設計 現在想購買咖啡時,可以要求在其中加入各種調料,如蒸奶 steamed milk 豆漿 soy...