1. 程式人生 > >工廠方法模式(Factory Method Pattern)。

工廠方法模式(Factory Method Pattern)。

定義:

定義一個用於建立物件的介面,讓子類決定例項化哪一個類。工廠方法使一個類的例項化延遲到其子類。

通用程式碼:

抽象產品類(Product)負責定義產品的共性

public abstract clas Product {

// 產品類的公共方法

public void method1(){

// 業務邏輯處理

}

// 抽象方法

public abstract void method2();

}

具體產品類(可以有多個,都繼承於抽象產品類)

pubilc class ConcreteProduct1 extends Product {

public void method2(){

// 業務邏輯處理

}

}


pubilc class ConcreteProduct2 extends Product {

public void method2(){

// 業務邏輯處理

}

}

抽象工廠類(Creator為抽象建立類,也就是抽象工廠,負責定義產品)

public abstract class Creator {

/*

 * 建立一個產品物件,其輸入引數型別可以自行設定

 * 通常為String、Enum、class等,當然也可以為空

 */

public abstract <T extends Product> T createProduct(Class<T> c);

}

具體工廠類(具體如何產生一個產品的物件,是由具體的工廠類建立的)

 

public class ConcreteCreator extends Creator {

public <T extends Product> T createProduct(Class<T> c) {

Product product = null;

try{

product = (Product) Class.forName(c.getName()).nextInstance();

} catch (Exception e) {

// 異常處理

}

return (T) product;

}

}

場景類

public class Client {

public static void main(String[] args) {

Creator creator = new ConcreteCreator();

Product product = creator.createProduct(ConcreteProduct1.class);

// 繼續業務處理

}

}

優點:

  • 良好的封裝性,程式碼結構清晰。
  • 工廠方法模式的擴充套件性非常優秀。
  • 遮蔽產品類。
  • 工廠方法模式時典型的解耦框架。

使用場景:

  • 工廠方法模式是new一個物件的替代品,所以在需要生成物件的地方都可以使用,但是需要慎重的考慮是否增加一個工廠類進行管理,增加程式碼的複雜度。
  • 需要靈活的、可擴充套件的框架時,可以考慮採用工廠方法模式。
  • 工廠方法模式可以用在異構專案中。
  • 可以使用在測試驅動開發的框架下。例如,測試一個類A,就需要把與類A有關聯關係的類B也同時產生出來,我們可以使用工廠方法模式把類B虛擬出來,避免類A與類B的耦合。目前由於JMock和EasyMock的誕生,該使用場景已經弱化了,讀者可以在遇到此種情況時直接考慮使用JMock或EazyMock。

工廠方法模式的擴充套件

1、縮小為簡單工廠模式

簡單工廠模式(Simple Factory Pattern),也叫作靜態工廠模式。在實際專案中,採用該方法的案例還是比較多的,其缺點是工廠類的擴充套件比較困難,不符合開閉原則,但它仍然是一個非常實用的設計模式。

2、升級為多個工廠類

在複雜的應用中一般採用多工廠的方法,然後再增加一個協調類,避免呼叫者與各個子工廠交流,協調類的作用是封裝子工廠了類,對高層模組提供統一的方法介面。

3、替代單例模式

負責生成單例的工廠類

public class SingletonFactory {

private static Singleton singleton;

static{

try{

Class cl  = Class.forName(Singleton.class.getName());

// 獲得無參構造

Constructor constructor = cl.getDeclaredConstructor();

// 設定無參構造是可以訪問的

constructor.setAccessible(true);

// 產生一個例項物件

singleton = (Singleton) constructor.newInstance()

} catch (Exception e) {

// 異常處理

}

}


public static Singleton getSingleton() {

return singleton;

}

}

4、延遲初始化(Lazy initialization)

定義:一個物件被消費完畢後,並不立即釋放,工廠類保持其初始狀態,等待再次被使用。

延遲載入的工廠類

public class ProductFactory {

private static final Map<String , Product> prMap = new HashMap();

public static synchronized Product createProduct(String type) throws Exception {

Product product = null;

// 如果Map中已經有這個物件

if(prMap.containsKey(type)) {

product = prMap.get(type);

} else {

if("Product1".equals(type)) {

product = new ConcreteProduct1();

} else {

product = new ConcreteProduct2();

}

// 同時把物件放到快取容器中

prMap.put(type.product);

}

return product;

}

}

延遲載入框架時可以擴充套件的,例如限制某一個產品類的最大例項化數量,可以通過判斷Map中已有的物件數量來實現,這樣的處理是非常有意義的,例如JDBC連線資料庫,都會要求社會一個MaxConnections最大連線數量,該數量就是記憶體中最大例項化的數量。

延遲載入還可以用在物件初始化比較複雜的情況下,例如硬體訪問,涉及多方面的互動,則可以通過延遲載入降低物件的產生和銷燬帶來的複雜性。

最佳實踐:

工廠方法模式在專案中使用得非常頻繁,以至於很多程式碼中都包含工廠方法模式。該模式近乎人盡皆知,但不是每個人都能用得好。熟能生巧,熟練掌握該模式,多思考工廠方法如何應用,而且工廠方法模式還可以與其他模式混合使用(例如模板方法模式、單例模式、原型模式燈),變化出無窮的優秀設計,這也正是軟體設計和開發的樂趣所在。

案例(女媧造人):

人類總稱

public interface Human {

// 每個人種的面板都有相應的顏色

public void getColor();

// 人類會說話

public void talk();

}

黑色人種(黃色人種和白色人種省略)

public class BlackHuman implements Human {

public void getColor() {

System.out.println("黑色人種的面板顏色是黑色的!");

}

public void talk(){

System.out.println("黑人會說話,一般人聽不懂。");

}

}

抽象人類建立工廠

public abstract class AbstractHumanFactory {

public abstract <T extends Human> T createHuman(Class<T> c);

}

注意,我們在這裡採用了泛型(Generic),通過定義泛型對createHuman的輸入引數產生兩層限制:

  • 必須是Class型別;
  • 必須是Human的實現類。

其中的“T”表示的是,只要實現了Human介面的類都可以作為引數,泛型是JDK1.5中的一個非常重要的新特性,它減少了物件間的轉換,約束其輸入引數型別,對Collection集合下的實現類都可以定義泛型。

人類建立工廠

public class HumanFactory extends AbstractHumanFactory {

public <T extends Human> T createHuman(Class<T> c) {

// 定義一個生產的人種

Human human = null;

try {

// 產生一個人種

human = (T) Class.forName(c.getName()).newInstrance();

} catch (Exception e) {

System.out.println("人種生成錯誤!");

}

return (T) human;

}

}

女媧類
 

public class NvWa {

public static void main(String[] args) {

// 宣告陰陽八卦爐

AbstractHumanFactory YinYangLu = new HumanFactory();

// 產生黑人

Human blackHuman = YinYangLu.createHuman(BlackHuman .class);

blackHuman.getColor();

blackHuman.talk(); 

}

}

簡單工廠模式中的工廠類

public class HumanFactory {

public  static <T extends Human> T createHuman(Class<T> c) {

// 定義一個生產的人種

Human human = null;

try {

// 產生一個人種

human = (T) Class.forName(c.getName()).newInstrance();

} catch (Exception e) {

System.out.println("人種生成錯誤!");

}

return (T) human;

}

}

女媧類
 

public class NvWa {

public static void main(String[] args) {

// 宣告陰陽八卦爐

AbstractHumanFactory YinYangLu = new HumanFactory();

// 產生黑人

Human blackHuman = HumanFactory.createHuman(BlackHuman .class);

blackHuman.getColor();

blackHuman.talk(); 

}

}

多工廠模式的抽象工廠類

public abstract class AbstractHumanFactory {

public abstract  Human createHuman();

}

黑色人種的建立工廠實現(白色人種和黃色人種省略)

public class BlackHumanFactory extends AbstractHumanFactory {
public Human createHuman() {

return new BlackHuman();

}
}

女媧類

public class NvWa {

public static void main(String[] args) {

// 宣告陰陽八卦爐

AbstractHumanFactory YinYangLu = new HumanFactory();

// 產生黑人

Human blackHuman = (new BlackHumanFactory()).createHuman(BlackHuman .class);

blackHuman.getColor();

blackHuman.talk(); 

}

}