程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> 關於JAVA >> 在Java中應用Factory Method設計模式

在Java中應用Factory Method設計模式

編輯:關於JAVA

在設計模式中,Factory Method也是比較簡單的一個,但應用非常廣泛,EJB,RMI,COM,CORBA,Swing中都可以看到此模式的影子,它是最重要的模式之一。在很多地方我們都會看到xxxFactory這樣命名的類,那麼,什麼是Factory Method,為什麼要用這個模式,如何用Java語言來實現該模式,這就是本文想要帶給大家的內容。

基本概念

Factory Method是一種創建性模式,它定義了一個創建對象的接口,但是卻讓子類來決定具體實例化哪一個類。當一個類無法預料要創建哪種類的對象或是一個類需要由子類來指定創建的對象時我們就需要用到Factory Method 模式了。

簡單說來,Factory Method可以根據不同的條件產生不同的實例,當然這些不同的實例通常是屬於相同的類型,具有共同的父類。Factory Method把創建這些實例的具體過程封裝起來了,簡化了客戶端的應用,也改善了程序的擴展性,使得將來可以做最小的改動就可以加入新的待創建的類。 通常我們將Factory Method作為一種標准的創建對象的方法,當發現需要更多的靈活性的時候,就開始考慮向其它創建型模式轉化。

簡單分析

圖1是Factory Method 模式的結構圖,這裡提供了一些術語,讓我們可以進行更方便的描述:

圖1: Factory Method 模式結構

1.Product: 需要創建的產品的抽象類。

2.ConcreteProduct: Product的子類,一系列具體的產品。

3.Creator: 抽象創建器接口,聲明返回Product類型對象的Factory Method。

4.ConcreteCreator: 具體的創建器,重寫Creator中的Factory Method,返回ConcreteProduct類型的實例。

由此可以清楚的看出這樣的平行對應關系:

Product <====> Creator ;

ConreteProduct <====> ConreteCreator

抽象產品對應抽象創建器,具體產品對應具體創建器。這樣做的好處是什麼呢?為什麼我們不直接用具體的產品和具體的創建器完成需求呢?實際上我們也可以這樣做。但通過Factory Method模式來完成,客戶(client)只需引用抽象的Product和Creater,對具體的ConcreteProduct和ConcreteCreator可以毫不關心,這樣做我們可以獲得額外的好處。

首先客戶端可以統一從抽象創建器獲取產生的實例,Creator的作用將client和產品創建過程分離開來,客戶不用操心返回的是那一個具體的產品,也不用關心這些產品是如何創建的。

同時,ConcreteProduct也被隱藏在Product後面,ConreteProduct繼承了Product的所有屬性,並實現了Product中定義的抽象方法,按照Java中的對象造型(cast)原則,通過ConcreteCreator產生的ConcreteProduct可以自動的上溯造型成Product。這樣一來,實質內容不同的ConcreteProduct就可以在形式上統一為Product,通過Creator提供給client來訪問。

其次,當我們添加一個新的ConcreteCreator時,由於Creator所提供的接口不變,客戶端程序不會有絲毫的改動,不會帶來動一發而牽全身的災難, 這就是良好封裝性的體現。但如果直接用ConcreteProduct和ConcreteCreator兩個類是無論如何也做不到這點的。

優良的面向對象設計鼓勵使用封裝(encapsulation)和委托(delegation),而Factory Method模式就是使用了封裝和委托的典型例子,這裡封裝是通過抽象創建器Creator來體現的,而委托則是通過抽象創建器把創建對象的責任完全交給具體創建器ConcreteCreator來體現的。

現在,請再回頭看看基本概念中的那段話,開始也許覺得生澀難懂,現在是不是已經明朗化了很多。

下面讓我們看看在 Java 中如何實現Factory Method模式,進一步加深對它的認識。

具體實施

先說明一點,用Factory Method模式創建對象並不一定會讓我們的代碼更短,實事上往往更長,我們也使用了更多的類,真正的目的在於這樣可以靈活的,有彈性的創建不確定的對象。而且,代碼的可重用性提高了,客戶端的應用簡化了,客戶程序的代碼會大大減少,變的更具可讀性。

標准實現: 這裡我采用Bruce Eckel 用來描述OO思想的經典例子 Shape。這樣大家會比較熟悉一些。我完全按照圖1中所定義的結構寫了下面的一段演示代碼。這段代碼的作用是創建不同的Shape實例,每個實例完成兩個操作:draw和erase。具體的創建過程委托?ShapeFactory來完成。

1.a 首先定義一個抽象類Shape,定義兩個抽象的方法。

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,實現Shape中定義的抽象方法

// 圓形子類
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.");
}
// 構造函數
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.");
}
// 構造函數
public Square(String aName)
{
super(aName);
}
}

1.c 定義抽象的創建器,anOperation調用factoryMethod創建一個對象,並對該對象進行一系列操作。

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相對應的兩個具體創建器CircleFactory,SquareFactory,實現父類的methodFactory方法

// 定義返回 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 測試類:請注意這個客戶端程序多麼簡潔,既沒有羅嗦的條件判斷語句,也無需關心ConcreteProduct和ConcreteCreator的細節(因為這裡我用anOperation封裝了Product裡的兩個方法,所以連Product的影子也沒看見,當然把Product裡方法的具體調用放到客戶程序中也是不錯的)。

class Main
{
public static void main(String[] args)
{
ShapeFactory sf1 = new SquareFactory();
ShapeFactory sf2 = new CircleFactory();
sf1.anOperation("Shape one");
sf2.anOperation("Shape two");
}
}

運行結果如下:

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.

參數化的Factory Method: 這種方式依靠指定的參數作為標志來創建對應的實例,這是很常見的一種辦法。比如JFC中的BorderFactory就是個很不錯的例子。

以下的這個例子是用字符串作為標記來進行判斷的,如果參數的類型也不一樣,那就可以用到過載函數來解決這個問題,定義一系列參數和方法體不同的同名函數,這裡java.util.Calendar.getInstance()又是個極好的例子。

參數化的創建方式克服了Factory Method模式一個最顯著的缺陷,就是當具體產品比較多時,我們不得不也建立一系列與之對應的具體構造器。 但是在客戶端我們必須指定參數來決定要創建哪一個類。

2.a 我們在第一種方法的基礎上進行修改,首先自定義一個的異常,這樣當傳入不正確的參數時可以得到更明顯的報錯信息。

class NoThisShape extends Exception
{
public NoThisShape(String aName)
{
super(aName);
}
}

2.b 去掉了ShapeFactory的兩個子類,改為由ShapeFactory直接負責實例的創建。 ShapeFactory自己變成一個具體的創建器,直接用參數化的方法實現factoryMethod返回多種對象。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved