前言 國際慣例,本文仍然是在學習設計模式的路上所寫,希望對同樣在學習設計模式的童靴有點作用,大牛誤入的話還請給點寶貴意見,感激不盡。 另外最近好尷尬,公司外網全部給撤了,白天又沒有什麼事情乾,好TM尷尬,本來想著趁著最近沒事趕緊把設計模式看完寫完的,誰知道來這麼個事情,好尷尬,只能晚上加班寫了,白天 ...
前言
國際慣例,本文仍然是在學習設計模式的路上所寫,希望對同樣在學習設計模式的童靴有點作用,大牛誤入的話還請給點寶貴意見,感激不盡。
另外最近好尷尬,公司外網全部給撤了,白天又沒有什麼事情乾,好TM尷尬,本來想著趁著最近沒事趕緊把設計模式看完寫完的,誰知道來這麼個事情,好尷尬,只能晚上加班寫了,白天睡覺,只想說一句MDZZ.
模式解析
好了,不廢話,今天繼續來學習設計模式中的抽象工廠模式,前面我們已經學習了簡單工廠模式和工廠方法模式,抽象工廠模式是工廠模式中的最後一個也是最複雜的一個。
首先,我們來看一下百度百科對抽象工廠模式的定義:
為創建一組相關或者相互依賴的對象提供一個介面,而且無需指定他們的具體類。
什麼意思呢?就是說現在要創建一組對象,這組對象是相關的或者是相互依賴的,但是在創建這組對象的時候我們會提供一個介面,使用這個介面來創建這組對象,並且在創建對象時創建的並不是具體類而是抽象類。
這麼說可能有的朋友還是不太明白,那麼我們來看一下抽象工廠的類圖:
在類圖中有這麼幾種對象,分別是Creator、ConcreteCreator、Product、Product1,跟上面定義中的名詞的對應關係分別是:
Creator對應上面的介面;
Product對應要創建的一組對象;
ConcreateCreator則是生產對象的工廠;
並且定義中說到無需指定他們的具體類,那麼在創建對象時返回的一定是抽象類或者介面,很顯然就是Product而非他的實現類;
上面定義也說了,類圖也給出了,下麵我們使用代碼的方式將上述的類圖展示出來:
首先就是Creator介面,用來生成產品的介面:
public interface Creator {
public ProductA createA();
public ProductB createB();
}
再者是介面的具體實現類,在實現類中來生成產品:
public class ProductFactoryA implements Creator{
@Override
public ProductA createA(){
return new ProductA1();
}
@Override
public ProductB createB(){
return new ProductB1();
}
}
public class ProductFactoryB implements Creator{
@Override
public ProductA createA(){
return new ProductA2();
}
@Override
public ProductB createB(){
return new ProductB2();
}
}
最後是類圖右半部分的具體產品以及產品的實現類:
public interface ProductA {
public void methodA();
}
public class ProductA1 implements ProductA{
@Override
public void methodA() {
System.out.println("產品A系列中的A1產品");
}
}
public class ProductA2 implements ProductA{
@Override
public void methodA() {
System.out.println("產品A系列中的A2產品");
}
}
產品B及其實現類與產品A類似,在這裡就不再貼產品B的代碼了,下麵給出測試類及其測試結果:
public static void main(String[] args) {
Creator creator = new ProductFactoryA();
ProductA productA = creator.createA();
ProductB productB = creator.createB();
productA.methodA();
productB.methodB();
creator = new ProductFactoryB();
productA = creator.createA();
productB = creator.createB();
productA.methodA();
productB.methodB();
}
測試結果如下所示:
上面的示例代碼也看完了,是不是該說抽象工廠模式的優缺點,然後結束了?兄弟,你還是太年輕了啊,下麵我們先不說什麼優缺點,我們先來認識一個概念產品族,那麼什麼是產品族呢?
所謂的產品族,是指位於不同產品等級結構中功能相關聯的產品組成的家族,MDZZ,剛知道了個產品族的名詞,怎麼又跑出來一個產品等級結構呢,接著往下看。
我們還拿上面的例子來說,ProductA和ProductB就是兩個不同的產品等級結構,也就是說在抽象工廠模式中,有幾個產品系列就有幾個產品等級結構,然後什麼是產品族呢?其中的ProductA1和ProductB1就屬於一個產品族,另外的另個屬於另一個產品族。
上面那麼說產品族可能不太好理解,我們舉個現實的例子,比如現在有兩種型號的車,分別是瑪莎拉蒂和勞斯萊斯,兩種車都有2.0和2.4兩種排量(說的不對別打我,畢竟窮屌絲就能意淫一下這種豪車了),那麼瑪莎拉蒂是一個產品等級結構,勞斯萊斯就是另外的一個產品等級結構,2.0排量的瑪莎拉蒂和2.0排量的勞斯萊斯是一個產品族,2.4排量的瑪莎拉蒂和2.4排量的勞斯萊斯是另外一個產品族,這樣來說的話大家應該好明白一點。
有兄弟說,樓主樓主你費半天勁解釋一個產品族有啥作用啊?作用就是下麵要說的抽象工廠模式和工廠方法模式的區別,同樣我們先把工廠方法模式的類圖放出來:
對比工廠方法模式和抽象工廠模式的類圖,大家有沒有發現什麼問題?對,其實就是工廠方法模式只有一個產品等級結構,但是抽象工廠模式可以有多個產品等級結構,可以說抽象工廠模式是工廠方法模式的擴展,只不過是針對多個產品等級結構的擴展。也就是說要區分抽象工廠模式和工廠方法模式最明顯的方式就是看產品等級結構的多少,如果只有一個,那麼肯定是工廠方法模式,如果多餘一個那麼肯定是抽象工廠模式沒跑了,下麵引用一個園子里左瀟龍大哥文章中一個真實的源碼的例子(原文地址)。
什麼例子呢?就是我們常用的集合List,下麵的內容均來自上述左蕭龍文章中,特此聲明,我們首先可以下list介面的部分源碼:
package java.util;
public interface List<E> extends Collection<E> {
Iterator<E> iterator();//一種產品
Object[] toArray();
<T> T[] toArray(T[] a);
ListIterator<E> listIterator();//另外一種產品
ListIterator<E> listIterator(int index);
}
LZ去掉了List介面中的很多方法,一是為了節省版面,另外是為了更清晰,我們主要關註iterator和listIterator方法,LZ在上面加了標註。
其中ListIterator是Iterator的子介面,但歸根到底,它其實屬於另外一種產品,為什麼這麼說呢,ListIterator不是Iterator的子介面嗎,怎麼能算是另外一種產品呢?這是因為我們listIterator方法的返回類型是ListIterator,而不是Iterator,所以兩者的功能是不同的,比如ListIterator還可以向前移動。
我們可以認為這兩個方法產生的一個是只能向後移動的迭代器,一個是可以前後移動的迭代器,這算是兩種產品,相當於上面的ProductA和ProductB。
這個設計可以看做是一個抽象工廠模式,List介面定義了兩種生產不同產品的方法,這屬於兩個系列的產品,不過由於產品介面本身的繼承關係,兩者的實現類也會被做成繼承的關係。下麵給出上面提到的介面的UML圖。
這個圖看起來有點複雜,各位可以和上面標準的抽象工廠模式類圖對比一下,下麵LZ來解釋一下在抽象工廠模式當中,上述幾個類都代表的什麼角色。
1.List,是抽象工廠的角色,它有兩個製造產品的方法,iterator和listIterator,相當於Creator。
2.ListIterator和Iterator都是抽象產品,相當於ProductA和ProductB。其中ListIterator有兩個實現類,分別是AbstractList.ListItr和LinkedList.ListItr,相當於ProductA1和ProductA2。Iterator的實現類為AbstractList.Itr,相當於ProductB1,但是沒有B2。
3.LinkedList是其中一個具體的工廠類,相當於ConcreteCreator1,實現抽象工廠List,它製造的兩個具體產品分別是LinkedList.ListItr和AbstractList.Itr。
4.同樣的,ArrayList也是一個具體的工廠類,相當於ConcreteCreator2,實現抽象工廠List,它製造的兩個具體產品分別是AbstractList.ListItr和AbstractList.Itr。
結合上一章工廠方法模式,我們來分析一下工廠方法模式和抽象工廠模式二者的關係。
Iterable介面是List的父介面,所以它只負責一個產品Iterator的製造,所以是工廠方法模式,而List介面擴展了Iterable介面,又添加了一個製造產品的方法,即又添加了一個系列的產品,所以就成為了抽象工廠模式。
沒分析過JDK源碼的人還是很少能分析的這麼透徹的吧,我這源碼都沒看過的人就不發表評論了,只是感覺好牛逼,轉載到自己文章中,省的哪天找不到,那就咖喱給給了啊。
真實的源碼例子也給大家找來了,我們下麵來對比一下三個工廠模式,從最簡單的簡單工廠模式到工廠方法模式再到最後的抽象工廠模式,這三者都是工廠模式,都屬於創建型設計模式,在形式和特點上是十分相似的,但是簡單工廠模式是違反開閉原則的,但是在工廠方法模式中彌補了這一點,但是工廠方法模式只有一個產品等級結構,使用抽象工廠模式也可以彌補,可以說這三個設計模式是層層遞進的關係,但是在本質上著三者是沒有太大的區別的,都是為了生成對象,至於選擇哪個模式就要看你的業務了,還是那句話,模式是死的,人是活的,靈活的選擇模式或者準確的來說靈活的使用設計模式是更重要的。
好了,今天這篇就到這裡了,優缺點使用場景什麼的說不說都一樣,下篇再見,下麵是最受觀眾喜愛的參考文章列表。
參考文章
- http://www.cnblogs.com/zuoxiaolong/p/pattern6.html
- http://blog.csdn.net/zhengzhb/article/details/7359385/