在 Java 中应用设计模式 - Factory Method
基本概念
FactoryMethod是一種創(chuàng)建性模式,它定義了一個創(chuàng)建對象的接口,但是卻讓子類來決定具體實例化哪一個類.當一個類無法預料要創(chuàng)建哪種類的對象或是一個類需要由子類來指定創(chuàng)建的對象時我們就需要用到Factory Method 模式了.簡單說來,Factory Method可以根據(jù)不同的條件產(chǎn)生不同的實例,當然這些不同的實例通常是屬于相同的類型,具有共同的父類.Factory Method把創(chuàng)建這些實例的具體過程封裝起來了,簡化了客戶端的應用,也改善了程序的擴展性,使得將來可以做最小的改動就可以加入新的待創(chuàng)建的類. 通常我們將Factory Method作為一種標準的創(chuàng)建對象的方法,當發(fā)現(xiàn)需要更多的靈活性的時候,就開始考慮向其它創(chuàng)建型模式轉(zhuǎn)化
簡單分析
圖1是Factory Method 模式的結(jié)構(gòu)圖,這里提供了一些術(shù)語,讓我們可以進行更方便的描述:
圖1: Factory Method 模式結(jié)構(gòu)
由此可以清楚的看出這樣的平行對應關(guān)系: Product <====> Creator ; ConreteProduct <====> ConreteCreator
抽象產(chǎn)品對應抽象創(chuàng)建器,具體產(chǎn)品對應具體創(chuàng)建器.這樣做的好處是什么呢?為什么我們不直接用具體的產(chǎn)品和具體的創(chuàng)建器完成需求呢?實際上我們也可以這樣做.但通過Factory Method模式來完成,客戶(client)只需引用抽象的Product和Creater,對具體的ConcreteProduct和ConcreteCreator可以毫不關(guān)心,這樣做我們可以獲得額外的好處:
- 首先客戶端可以統(tǒng)一從抽象創(chuàng)建器獲取產(chǎn)生的實例,Creator的作用將client和產(chǎn)品創(chuàng)建過程分離開來,客戶不用操心返回的是那一個具體的產(chǎn)品,也不用關(guān)心這些產(chǎn)品是如何創(chuàng)建的.同時,ConcreteProduct也被隱藏在Product后面,ConreteProduct繼承了Product的所有屬性,并實現(xiàn)了Product中定義的抽象方法,按照Java中的對象造型(cast)原則,通過ConcreteCreator產(chǎn)生的ConcreteProduct可以自動的上溯造型成Product.這樣一來,實質(zhì)內(nèi)容不同的ConcreteProduct就可以在形式上統(tǒng)一為Product,通過Creator提供給client來訪問.
- 其次,當我們添加一個新的ConcreteCreator時,由于Creator所提供的接口不變,客戶端程序不會有絲毫的改動,不會帶來動一發(fā)而牽全身的災難, 這就是良好封裝性的體現(xiàn).但如果直接用ConcreteProduct和ConcreteCreator兩個類是無論如何也做不到這點的. 優(yōu)良的面向?qū)ο笤O計鼓勵使用封裝(encapsulation)和委托(delegation),而Factory Method模式就是使用了封裝和委托的典型例子,這里封裝是通過抽象創(chuàng)建器Creator來體現(xiàn)的,而委托則是通過抽象創(chuàng)建器把創(chuàng)建對象的責任完全交給具體創(chuàng)建器ConcreteCreator來體現(xiàn)的.
現(xiàn)在,請再回頭看看基本概念中的那段話,開始也許覺得生澀難懂,現(xiàn)在是不是已經(jīng)明朗化了很多.
下面讓我們看看在 Java 中如何實現(xiàn)Factory Method模式,進一步加深對它的認識.
具體實施
先說明一點,用Factory Method模式創(chuàng)建對象并不一定會讓我們的代碼更短,實事上往往更長,我們也使用了更多的類,真正的目的在于這樣可以靈活的,有彈性的創(chuàng)建不確定的對象.而且,代碼的可重用性提高了,客戶端的應用簡化了,客戶程序的代碼會大大減少,變的更具可讀性.
1.a 首先定義一個抽象類Shape,定義兩個抽象的方法.
| 1 2 3 4 5 6 7 8 9 10 | abstract class Shape { ??// 勾畫shape ??public abstract void draw(); ??// 擦去 shape ??public abstract void erase(); ??public String name; ??public Shape(String aName){ ????name = aName; ??} } |
1.b 定義 Shape的兩個子類: Circle, Square,實現(xiàn)Shape中定義的抽象方法
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | // 圓形子類 class Circle extends Shape { ??public void draw() { ????System.out.println("It will draw a circle."); ??} ??public void erase() { ????System.out.println("It will erase a circle."); ??} ??// 構(gòu)造函數(shù) ??public Circle(String aName){ ????super(aName); ??} } // 方形子類 class Square extends Shape { ??public void draw() { ????System.out.println("It will draw a square."); ??} ??public void erase() { ????System.out.println("It will erase a square."); ??} ??// 構(gòu)造函數(shù) ??public Square(String aName){ ????super(aName); ??} } |
1.c 定義抽象的創(chuàng)建器,anOperation調(diào)用factoryMethod創(chuàng)建一個對象,并對該對象進行一系列操作.
| 1 2 3 4 5 6 7 8 9 10 | abstract class ShapeFactory {? ??protected abstract Shape factoryMethod(String aName); ??// 在anOperation中定義Shape的一系列行為 public void anOperation(String aName){ ????Shape s = factoryMethod(aName); ????System.out.println("The current shape is: " + s.name); ????s.draw(); ????s.erase(); ??} } |
1.d 定義與circle和square相對應的兩個具體創(chuàng)建器CircleFactory,SquareFactory,實現(xiàn)父類的methodFactory方法
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | // 定義返回 circle 實例的 CircleFactory class CircleFactory extends ShapeFactory { ??// 重載factoryMethod方法,返回Circle對象 ??protected Shape factoryMethod(String aName) { ????return new Circle(aName + " (created by CircleFactory)"); ??} } ??? // 定義返回 Square 實例的 SquareFactory class SquareFactory extends ShapeFactory { ??// 重載factoryMethod方法,返回Square對象 protected Shape factoryMethod(String aName) { ????return new Square(aName + " (created by SquareFactory)"); ??} } |
1.e 測試類:請注意這個客戶端程序多么簡潔,既沒有羅嗦的條件判斷語句,也無需關(guān)心ConcreteProduct和ConcreteCreator的細節(jié)(因為這里我用anOperation封裝了Product里的兩個方法,所以連Product的影子也沒看見,當然把Product里方法的具體調(diào)用放到客戶程序中也是不錯的).
| 1 2 3 4 5 6 7 8 | class Main { ??public static void main(String[] args){ ????ShapeFactory sf1 = new SquareFactory(); ????ShapeFactory sf2 = new CircleFactory(); ????sf1.anOperation("Shape one"); ????sf2.anOperation("Shape two"); ??} } |
運行結(jié)果如下:
The current shape is: Shape one (created by SquareFactory)
It will draw a square.
It will erase a square.
The current shape is: Shape two (created by CircleFactory)
It will draw a circle.
It will erase a circle.
2.a 我們在第一種方法的基礎上進行修改,首先自定義一個的異常,這樣當傳入不正確的參數(shù)時可以得到更明顯的報錯信息.
| 1 2 3 4 5 | class NoThisShape extends Exception { ??public NoThisShape(String aName) { ????super(aName); ??} } |
2.b去掉了ShapeFactory的兩個子類,改為由ShapeFactory直接負責實例的創(chuàng)建. ShapeFactory自己變成一個具體的創(chuàng)建器,直接用參數(shù)化的方法實現(xiàn)factoryMethod返回多種對象.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | abstract class ShapeFactory {? ??private static Shape s; ??private ShapeFactory() {} ????? ??static Shape factoryMethod(String aName, String aType) throws NoThisShape{ ????if (aType.compareTo("square")==0) ??????return new Square(aName); ????else if (aType.compareTo("circle")==0) ??????return new Circle(aName); ????else throw new NoThisShape(aType);? ??} ??? ??// 在anOperation中定義Shape的一系列行為 ??static void anOperation(String aName, String aType) throws NoThisShape{ ????s = factoryMethod(aName, aType); ????System.out.println("The current shape is: " + s.name); ????s.draw(); ????s.erase(); ??} } |
2.c 測試類:這里客戶端必須指定參數(shù)來決定具體創(chuàng)建哪個類.這個例子里的anOperation是靜態(tài)函數(shù),可以直接引用.
| 1 2 3 4 5 6 7 | class Main { ??public static void main(String[] args) throws NoThisShape{ ????ShapeFactory.anOperation("Shape one","circle"); ????ShapeFactory.anOperation("Shape two","square"); ????ShapeFactory.anOperation("Shape three", "delta"); ??} } |
運行結(jié)果如下:
| 1 2 3 4 5 6 7 8 9 10 | The current shape is: Shape one It will draw a circle. It will erase a circle. The current shape is: Shape two It will draw a square. It will erase a square. Exception in thread "main" NoThisShape: delta ????????at ShapeFactory.factoryMethod(ShapeFactory.java:10) ????????at ShapeFactory.anOperation(ShapeFactory.java:15) ????????at Main.main(Main.java:5) |
有的時候我們會把ConcreteProduct的實例傳給創(chuàng)建器作為參數(shù),這種情況下,如果在創(chuàng)建器里完成創(chuàng)建過程,就必須判斷參數(shù)的具體類型(用instanceof),然后才能產(chǎn)生相應的實例,那么比較好的做法是利用Java的動態(tài)裝載機制來完成這件事.比如:
我們得到一個Shape的子類s,但不知道具體是那個子類,就可以利用Class類自帶的方法newInstance()得到實例
return (Shape)s.getClass().newInstance();
這種方法有興趣得讀者可以自己嘗試,限于篇幅,不寫具體代碼出來了.
后話:
看完這篇文章后,相信讀者對Factory Method模式有一個比較清楚的了解了.我想說的是,我們不僅應該關(guān)心一個具體的模式有什么作用,如何去實現(xiàn)這個模式,更應該透過現(xiàn)象看本質(zhì),不但知其然,還要知其所以然.要通過對模式的學習加深對面向?qū)ο笏枷氲睦斫?讓自己的認識得到升華.Factory Method模式看似簡單,實則深刻.抽象,封裝,繼承,委托,多態(tài),針對接口編程等面向?qū)ο笾械母拍疃荚谶@里得到了一一的體現(xiàn).只有抓住了它的本質(zhì),我們才能夠不拘于形式的靈活運用,而不是為了使用模式而使用模式.
相關(guān)主題
- Thinking in Pattern with Java ---- Bruce Eckel
- The Factory Method Design Pattern by Gopalan Suresh Raj----http://gsraj.tripod.com/design/creational/factory/factory.html
- SENG609_40 FACTORY PATTERNS PAPER----http://sern.ucalgary.ca/~kjfu/courses/SENG60904/paper.html
- Factory Method Pattern----?http:// www.ugolandini.net/FactoryMethodPattern.html
- Design Patterns in Java ---- Bob Tarr
- Design Patterns ---- Gang of Four
- Dynamic Class Loading in Java----?http:// www.pramodx.20m.com/dynamic_class_loading_in_java.htm
總結(jié)
以上是生活随笔為你收集整理的在 Java 中应用设计模式 - Factory Method的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: java 常用十种设计模式示例归纳 |
- 下一篇: CSS 基础语法