一、簡(jiǎn)單工廠
舉個(gè)栗子:
開個(gè)披薩店:
Pizza orderPizza() {
Pizza pizza = new Pizza(); //創(chuàng)建個(gè)pizza
pizza.prepare(); //備料
pizza.bake(); //烘烤
pizza.cut(); //切片
pizza.box(); //裝盒
}
披薩店不能只有一種披薩,要做各種類型的披薩怎么辦呢?
Pizza orderPizza(String type) {//要做什么pizza就傳入pizza的種類
Pizza pizza;
if (type.equals(“cheese”)) { //根據(jù)pizza的類型,來(lái)實(shí)例化正確的具體類
pizza = new CheesePizza();
} else if ...
pizza.prepare(); //備料
pizza.bake(); //烘烤
pizza.cut(); //切片
pizza.box(); //裝盒
}
披薩店擴(kuò)張了,制作的披薩種類更多了,有些披薩賣得不好,不做了,這怎么做呢?
只能在上面代碼里刪掉一些if else,再添加上一些if else。在上面這段代碼中,if else這段會(huì)隨著需求的變化而變化,但對(duì)披薩的備料,烘烤等操作是不會(huì)變化的。
Tips:
開閉原則:
擴(kuò)展開放,對(duì)修改關(guān)閉。一個(gè)軟件實(shí)體應(yīng)該通過(guò)擴(kuò)展來(lái)實(shí)現(xiàn)變化,而不是通過(guò)修改已有代碼來(lái)實(shí)現(xiàn)變化。
很明顯,上面的這種設(shè)計(jì),違背了開閉原則,這就到了使用封裝的時(shí)候了。把會(huì)經(jīng)常修改的if else這段代碼抽離到另一個(gè)對(duì)象中,這個(gè)對(duì)象只負(fù)責(zé)創(chuàng)建披薩。
這個(gè)新對(duì)象SimplePizzaFactory就稱為“工廠”,專門用來(lái)生產(chǎn)不同種類的披薩,orderPizza()就是這個(gè)對(duì)象的客戶,當(dāng)需要披薩時(shí),就叫披薩工廠做一個(gè),至于怎么做,就不用關(guān)心了。
賣披薩分三步:
1.建個(gè)披薩工廠專門做披薩
public class SimplePizzaFactory { //只負(fù)責(zé)創(chuàng)建披薩
public Pizza createPizza(String type) { //這個(gè)方法為所有用戶實(shí)例化新對(duì)象
Pizza pizza = null;
if (type.equals(“cheese”)) { //之前的if else
pizza = new CheesePizza();
} else if ...
return pizza;
}
}
2.建個(gè)披薩店
public class PizzaStore {
SimplePizzaFactory factory; //為披薩店P(guān)izzaStore加上對(duì)SimplePizzaFactory的引用
public PizzaStore (SimplePizzaFactory factory) { //披薩店P(guān)izzaStore的構(gòu)造器,以一個(gè)工廠做參數(shù)
This.factory = factory;
}
public Pizza orderPizza (String type) {
Pizza pizza;
pizza = factory.createPizza(type);//通過(guò)傳入類型來(lái)使用工廠加工披薩
pizza.prepare(); //備料
pizza.bake(); //烘烤
...
return pizza;
}
}
3.披薩賣起來(lái)了
pubic class PizzaTest {
public static void main (String[] args) {
SimplePizzaFactory factory = new SimplePizzaFactory();//創(chuàng)建一個(gè)披薩工廠
PizzaStore story = new PizzaStore(factory); //建立一個(gè)披薩店,從披薩工廠里獲取披薩
store.orderPizza(“Cheese”);//選擇披薩的具體口味
}
}
簡(jiǎn)單工廠其實(shí)不是一個(gè)設(shè)計(jì)模式,反而比較像一種編程習(xí)慣,把變化的部分單獨(dú)封裝起來(lái)。
二、工廠模式
披薩店有了加盟店啦~~但是每個(gè)加盟店想提供適合自己所在區(qū)域口味的披薩,所以加盟店需要有一個(gè)適合自己的工廠。
還是賣披薩的那三步:
1.建一個(gè)專門生產(chǎn)紐約風(fēng)味的披薩工廠
abstract class PizzaFactory {
public abstract Pizza createPizza();
}
public class NYPizzaFactory extent PizzaFactory {//繼承抽象工廠類,創(chuàng)建具體的實(shí)例方法
public Pizza createPizza(String type) {
... //個(gè)性化定制紐約口味披薩
return pizza;
}
}
2.開個(gè)加盟店
到這里發(fā)現(xiàn),加盟店也需要個(gè)性化定制啊,不能通用就是PizzaStore,也得有什么NYPizzaStore啊,那就把披薩店也抽象出來(lái)。
public abstract class PizzaStore { //創(chuàng)建一個(gè)抽象的披薩店P(guān)izzaStore類
public Pizza orderPizza(String type) {//處理披薩訂單
Pizza pizza;
pizza = createPizza(type);//調(diào)用的就是下方的createPizza方法,這個(gè)方法由各個(gè)加盟店自己定義,也就是說(shuō)每個(gè)PizzaStore的子類都會(huì)覆蓋createPizza()方法
//pizza的后續(xù)制作不變,加盟店無(wú)法影響他們,加盟店只負(fù)責(zé)確定口味,在外部調(diào)用orderPizza,而orderPizza里的createPizza是加盟店自己定義的具體制作什么口味的披薩
pizza.prepare(); //備料
pizza.bake(); //烘烤
...
return pizza;
}
protected abstract Pizza createPizza(String type);//由各個(gè)加盟店自己決定如何做披薩
}
現(xiàn)在就開個(gè)加盟店
public class NYPizzaStore extends PizzaStore {
Pizza createPizza(String item) { //必須實(shí)現(xiàn)createPizza()方法,因?yàn)樵赑izzaStore里他是抽象的
if (item.equals(“cheese”)) { //具體的披薩口味
return new NYStyleCheesePizza();
} else if ...
}
}
3.賣個(gè)紐約風(fēng)味的芝士披薩
public class PizzaTest {
public Static void main(String[] args) {
PizzaStroe nyStore = new NYPizzaStore();//建個(gè)紐約加盟店
Pizza pizza = nyStore.orderPizza(“cheese”);//定個(gè)cheese披薩
}
}
Tips:
重點(diǎn)解釋abstract Pizza createPizza(String type);

工廠模式用來(lái)封裝對(duì)象的常見,通過(guò)讓子類決定應(yīng)該創(chuàng)建的對(duì)象,達(dá)到將對(duì)象創(chuàng)建的過(guò)程封裝起來(lái)的目的。
工廠方法模式:定義了一個(gè)創(chuàng)建對(duì)象的接口,但由子類決定要實(shí)例化的類是哪一個(gè)。工廠方法讓類把實(shí)例化推遲到子類。
工廠模式類圖:

三、抽象工廠模式
抽象工廠模式提供一個(gè)接口,用于創(chuàng)建相關(guān)或依賴對(duì)象的“家族”(敲黑板,重點(diǎn)),而不需要明確指定具體類。
抽象工廠的任務(wù)是定義一個(gè)負(fù)責(zé)創(chuàng)建一組產(chǎn)品的接口,這個(gè)接口內(nèi)的每個(gè)方法都負(fù)責(zé)創(chuàng)建一個(gè)具體產(chǎn)品,同時(shí)利用實(shí)現(xiàn)抽象工廠的子類來(lái)提供這些具體的做法。
工廠方法用的是繼承,而抽象工廠是通過(guò)對(duì)象的組合來(lái)實(shí)現(xiàn)。
再通過(guò)披薩店的例子,來(lái)看看抽象工廠模式。
還是賣披薩的那三步:
1.建立工廠
A.建一個(gè)專門生產(chǎn)紐約風(fēng)味的披薩工廠
abstract class PizzaFactory {
public abstract Pizza createPizza();
}
public class NYPizzaFactory extent PizzaFactory {//繼承抽象工廠類,創(chuàng)建具體的實(shí)例方法
public Pizza createPizza(String type) {
... //個(gè)性化定制紐約口味披薩
return pizza;
}
}
B.制作披薩所用的原料需要保證質(zhì)量,就需要建立一家生產(chǎn)原料的工廠,這樣每家加盟店都從這個(gè)原料工廠里進(jìn)貨,確保質(zhì)量。但是各個(gè)加盟店所產(chǎn)披薩的口味不同,所需原料也有細(xì)微差別(紐約的芝士和芝加哥的芝士,口味上是不一樣的),與建立披薩工廠的思想一樣,還是先建立一個(gè)原料生產(chǎn)工廠,然后每個(gè)區(qū)域繼承這個(gè)工廠,來(lái)生產(chǎn)自己各自口味的原料。
定義原料工廠接口,它負(fù)責(zé)創(chuàng)建所有的原料:
public interface PizzaIngredientFactory{
public Dough createDough(); //生產(chǎn)面團(tuán)
public Sauce createSauce(); //生產(chǎn)醬料
...
}
那么紐約原料工廠生產(chǎn)的原料就是紐約口味的啦
public class NYPizzaIngredientFactory implements PizzaIngredientFactory {
public Dough createDough() {
return new ThinCrustDough();
}
public Sauce createSauce() {
return new MarinaraSauce();
}
...
}
需要使用原料工廠生產(chǎn)出的原料來(lái)制作披薩
public abstract class Pizza {
Dough dough;
Sauce sauce;
...//制作披薩所需的各種原料
abstract void prepare();//把prepare()方法聲明成抽象,由不同地區(qū)的原料工廠提供原料
//之前的烘烤、切片等工序不變
void back() {
}
void cut() {
}
...
}
之后我們就可以使用原料工廠生產(chǎn)的原料來(lái)制作披薩啦,原料的質(zhì)量得到了保證。
制作一個(gè)芝士披薩
public class CheesePizza extends Pizza {
PizzaIngredientFactory ingredientFactory;
public CheesePizza (pizzaIngredientFactory ingredientFactory) {
this.ingredientFactory = ingredientFactory;
}
void prepare() {//從原料工廠里獲取原料制作披薩
dough = ingredientFactory.createDough();
Sauce = ingredientFactory.createSauce();
...
}
}
Tips:

2.開個(gè)加盟店
public class NYPizzaStore extends PizzaStore {
Protected Pizza createPizza(String item) {
Pizza pizza = null;
PizzaIngredientFactory ingredientFactory = new NYPizzaIngredientFactory();
if (item.equals(“cheese”)) {
//把工廠傳遞給每一個(gè)披薩,以便比薩從工廠中取得原料
//具體從哪個(gè)工廠(紐約工廠?芝加哥工廠?),由上面那行代碼決定
pizza = new CheesePizza(ingredientFactory);
} else if ...
return pizza;
}
}
3.賣個(gè)紐約風(fēng)味的芝士披薩
public class PizzaTest {
public Static void main(String[] args) {
PizzaStroe nyStore = new NYPizzaStore();//建個(gè)紐約加盟店
Pizza pizza = nyStore.orderPizza(“cheese”);//定個(gè)cheese披薩
}
}
看看抽象工廠的類圖

結(jié)合披薩店再來(lái)看

結(jié)合上面的類圖再回顧下抽象工廠的定義,抽象工廠的任務(wù)是定義一個(gè)負(fù)責(zé)創(chuàng)建“一組”產(chǎn)品的接口,通過(guò)對(duì)象的“組合”來(lái)實(shí)現(xiàn)。
在披薩店的例子中,創(chuàng)建了三個(gè)接口:披薩,披薩店,披薩原料工廠,通過(guò)組合這三個(gè)接口,實(shí)現(xiàn)了對(duì)各個(gè)加盟店的控制:保證披薩的制作工藝,和原料供應(yīng)