在物件導向程式設計, 最通常的方法是一個new運算子產生一個物件實例,new操作符就是用來建構物件實例的。但是在一些情況下, new操作符直接產生物件會帶來一些問題。舉例來說, 許多類型物件的創造需要一系列的步驟: 你可能需要計算或取得物件的初始設定; 選擇生成哪個子物件實例; 或在生成你需要的物件之前必須先生成一些輔助功能的物件。 在這些情況,新物件的建立就是一個 “過程”,不僅是一個操作,像一部大機器中的一個齒輪傳動。
模式的問題:你如何能輕鬆方便地建構物件實例,而不必關心建構物件實例的細節和複雜過程?
解決方案:建立一個工廠來創建對象
實現:
一、引言
1)還沒有工廠時代:假如還沒有工業革命,如果一個客戶要一款寶馬車,一般的做法是客戶去創建一輛寶馬車,然後拿來用。
2)簡單工廠模式:後來出現工業革命。使用者不用去創建寶馬車。因為客戶有一個工廠來幫他創建寶馬.想要什麼車,這個工廠就可以蓋。例如想要320i系列車。工廠就創造這個系列的車。即工廠可以創造產品。
3)工廠方法模式時代:為了滿足客戶,寶馬車系列越來越多,如320i,523i,30li等系列一個工廠無法創造所有的寶馬系列。於是由單獨分出來多個具體的工廠。每個具體工廠創建一種系列。即具體工廠類別只能創造一個具體產品。但是寶馬工廠還是個抽象。你需要指定某個具體的工廠才能生產車子出來。
4)抽象工廠模式時代:隨著顧客的要求越來越高,寶馬車必須配置空調。於是這個工廠開始生產BMW車和所需的空調。
最後是客戶只要對寶馬的銷售員說:我要523i冷氣車,銷售員就直接給他523i冷氣車了。而不用自己去創造523i冷氣車寶馬車.
這就是工廠模式。
二、分類
工廠模式主要是為創建對象提供過渡接口,以便將創建對象的具體過程屏蔽隔離起來,達到提高靈活性的目的。
工廠模式可分為三類:
1)簡單工廠模式(Simple Factory)
2)工廠方法模式(Factory Method)
3)抽象工廠模式(Abstract Factory)
這三種模式從上到下這三種模式從上到下這三種模式從上到下這三種模式從上到下這三種模式從上到下。逐步抽象,並且更具一般性。
GOF在《設計模式》一書中將工廠模式分為兩大類:工廠方法模式(Factory Method)與抽象工廠模式(Abstract Factory)。
將簡單工廠模式(Simple Factory)視為工廠方法模式的一種特例,兩者歸為一類。
三、區別
工廠方法模式:
一個抽象產品類,可以衍生出多個特定產品類別。
一個抽象工廠類,可以衍生出多個特定工廠類別。
每個特定工廠類別只能建立一個特定產品類別的實例。
抽象工廠模式:
多個抽象產品類,每個抽象產品類別可以衍生出多個特定產品類別。
一個抽象工廠類,可以衍生出多個特定工廠類別。
每個特定工廠類別可以建立多個特定產品類別的實例。
區別:
工廠方法模式只有一個抽象產品類,而抽象工廠模式有多個。
工廠方法模式的特定工廠類別只能建立一個特定產品類別的實例,而抽象工廠模式可以創建多個。
兩者皆可。
四、簡單工廠模式
建立一個工廠(一個函數或一個類別方法)來製造新的物件。
分佈說明引子:從無到有。客戶自己創造寶馬車,然後拿來用。
public class BMW320 { public BMW320(){ System.out.println("制造-->BMW320"); } } public class BMW523 { public BMW523(){ System.out.println("制造-->BMW523"); } } public class Customer { public static void main(String[] args) { BMW320 bmw320 = new BMW320(); BMW523 bmw523 = new BMW523(); } }
客戶需要知道怎麼去創建一款車,客戶和車就緊密耦合在一起了.為了降低耦合,就出現了工廠類,把創建寶馬的操作細節都放到了工廠裡面去,客戶直接使用工廠的創建工廠方法,傳入想要的寶馬車型號就行了,而不必去知道創建的細節.這就是工業革命了:簡單工廠模式
即我們建立一個工廠類方法來製造新的對象。如圖:
產品類:
abstract class BMW { public BMW(){ } } public class BMW320 extends BMW { public BMW320() { System.out.println("制造-->BMW320"); } } public class BMW523 extends BMW{ public BMW523(){ System.out.println("制造-->BMW523"); } }
工廠類:
public class Factory { public BMW createBMW(int type) { switch (type) { case 320: return new BMW320(); case 523: return new BMW523(); default: break; } return null; } }
客戶類:
public class Customer { public static void main(String[] args) { Factory factory = new Factory(); BMW bmw320 = factory.createBMW(320); BMW bmw523 = factory.createBMW(523); } }
简单工厂模式又称静态工厂方法模式。重命名上就可以看出这个模式一定很简单。它存在的目的很简单:定义一个用于创建对象的接口。
先来看看它的组成:
1) 工厂类角色:这是本模式的核心,含有一定的商业逻辑和判断逻辑,用来创建产品
2) 抽象产品角色:它一般是具体产品继承的父类或者实现的接口。
3) 具体产品角色:工厂类所创建的对象就是此角色的实例。在Java中由一个具体类实现。
下面我们从开闭原则(对扩展开放;对修改封闭)上来分析下简单工厂模式。当客户不再满足现有的车型号的时候,想要一种速度快的新型车,只要这种车符合抽象产品制定的合同,那么只要通知工厂类知道就可以被客户使用了。所以对产品部分来说,它是符合开闭原则的;但是工厂部分好像不太理想,因为每增加一种新型车,都要在工厂类中增加相应的创建业务逻辑(createBMW(int type)方法需要新增case),这显然是违背开闭原则的。可想而知对于新产品的加入,工厂类是很被动的。对于这样的工厂类,我们称它为全能类或者上帝类。
我们举的例子是最简单的情况,而在实际应用中,很可能产品是一个多层次的树状结构。由于简单工厂模式中只有一个工厂类来对应这些产品,所以这可能会把我们的上帝累坏了,也累坏了我们这些程序员。
于是工厂方法模式作为救世主出现了。 工厂类定义成了接口,而每新增的车种类型,就增加该车种类型对应工厂类的实现,这样工厂的设计就可以扩展了,而不必去修改原来的代码。
五、工厂方法模式
工厂方法模式去掉了简单工厂模式中工厂方法的静态属性,使得它可以被子类继承。这样在简单工厂模式里集中在工厂方法上的压力可以由工厂方法模式里不同的工厂子类来分担。
工厂方法模式组成:
1)抽象工厂角色: 这是工厂方法模式的核心,它与应用程序无关。是具体工厂角色必须实现的接口或者必须继承的父类。在java中它由抽象类或者接口来实现。
2)具体工厂角色:它含有和具体业务逻辑有关的代码。由应用程序调用以创建对应的具体产品的对象。
3)抽象产品角色:它是具体产品继承的父类或者是实现的接口。在java中一般有抽象类或者接口来实现。
4)具体产品角色:具体工厂角色所创建的对象就是此角色的实例。在java中由具体的类来实现。
工厂方法模式使用继承自抽象工厂角色的多个子类来代替简单工厂模式中的“上帝类”。正如上面所说,这样便分担了对象承受的压力;而且这样使得结构变得灵活 起来——当有新的产品产生时,只要按照抽象产品角色、抽象工厂角色提供的合同来生成,那么就可以被客户使用,而不必去修改任何已有 的代码。可以看出工厂角色的结构也是符合开闭原则的!
代码如下:
产品类:
abstract class BMW { public BMW(){ } } public class BMW320 extends BMW { public BMW320() { System.out.println("制造-->BMW320"); } } public class BMW523 extends BMW{ public BMW523(){ System.out.println("制造-->BMW523"); } }
创建工厂类:
interface FactoryBMW { BMW createBMW(); } public class FactoryBMW320 implements FactoryBMW{ @Override public BMW320 createBMW() { return new BMW320(); } } public class FactoryBMW523 implements FactoryBMW { @Override public BMW523 createBMW() { return new BMW523(); } }
客户类:
public class Customer { public static void main(String[] args) { FactoryBMW320 factoryBMW320 = new FactoryBMW320(); BMW320 bmw320 = factoryBMW320.createBMW(); FactoryBMW523 factoryBMW523 = new FactoryBMW523(); BMW523 bmw523 = factoryBMW523.createBMW(); } }
工厂方法模式仿佛已经很完美的对对象的创建进行了包装,使得客户程序中仅仅处理抽象产品角色提供的接口,但使得对象的数量成倍增长。当产品种类非常多时,会出现大量的与之对应的工厂对象,这不是我们所希望的。