1. 程式人生 > >工廠設計模式

工廠設計模式

throw 變種 row ets string abs 描述 設計模式 static

工廠設計模式:是一種創建對象的模式,使代碼的耦合。工廠模式就是給外部批量提供相同或者不同的產品,而外部不需要關心工廠是如何創建一個復雜產品的過程.所以工廠模式可以降低模塊間的耦合,同時可以提高擴展性(當有新的產品出現時,只需要擴展工廠就行了,上層模塊不敏感).

1:創建一個接口或者抽象類

2:實現接口(產品類)

3:創建一個工廠類:在工廠類裏面創建對象(產品的實例化類)

4:在客戶端創建工廠,得到我們想要創建的對象(客戶端的引用)

1.)標準工廠方法模式

首先先介紹一下標準的工廠方法模式,不帶任何的變種.以工廠生產不同操作系統的手機為例.

建立一個產品接口,提供一個獲取系統信息的方法.

/**
 * Created by jesse on 15-8-17.
 */
public interface IPhone {
    public void getOS();
}

再根據IPhone接口實現Android,IOS,Blackberry三種手機.

public class AndroidPhone implements IPhone {
    private final String TAG = AndroidPhone.class.getSimpleName();
    @Override
    public void getOS() {
        Log.i(TAG, "im Android");
    }
}
public class IosPhone implements IPhone {
    private final String TAG = IosPhone.class.getSimpleName();
    @Override
    public void getOS() {
        Log.i(TAG, "im IOS");
    }
}
public class BlackBerryPhone implements IPhone {
    private final String TAG = BlackBerryPhone.class.getSimpleName();
    @Override
    public void getOS() {
        Log.i(TAG, "im BlackBerry");
    }
}

標準的工廠方法模式都需要有抽象的工廠接口或者基類.

public abstract class IGenerator {
    public abstract IPhone generatePhone(String flag) throws Exception;
}

通過基類或者接口來實現真實的工廠類,這裏需要註意跟簡單工廠模式的不同,標準的工廠方法模式裏面一個工廠只生產一個產品,所以這裏要根據產品的種類劃分出來三個工廠,分別生產三種不同的產品.這種設計思想非常契合單一職責原則.

public class AndroidGenerator extends IGenerator {
    @Override
    public IPhone generatePhone() {
        return new AndroidPhone();
    }
}
public class IOSGenerator extends IGenerator {
    @Override
    public IPhone generatePhone() {
        return new IosPhone();
    }
}
public class BlackberryGenerator extends IGenerator {
    @Override
    public IPhone generatePhone() {
        return new BlackBerryPhone();
    }
}
在客戶端從工廠中獲得產品並使用的過程中都是通過接口進行訪問的,在創建產品的階段有效得降低了使用者和產品之間的耦合度.
AndroidGenerator  androidGenerator = new AndroidGenerator(); 
IOSGenerator   iosGenerator = new IOSGenerator(); 
BlackberryGenerator  bbGenerator = new BlackberryGenerator();
android = androidGenerator.generatePhone();
ios = iosGenerator.generatePhone();
bb = bbGenerator.generatePhone();
android.getOS();
ios.getOS();
bb.getOS();

2).簡單工廠模式

接著分析一下簡單工廠模式,這是最簡單的變種,也叫做靜態工廠方法模式,從這個名字就可以看出工廠的方法是靜態的.既然工廠方法是靜態的,那麽工廠就不能通過繼承進行擴展,如果有新增的產品,就只能在方法裏面做修改所以從這個角度來說簡單工廠模式是不符合開閉原則的.(工廠就是一個簡單的類,不是抽象類和接口) 因為這是靜態工廠方法模式,所以工廠類就沒有接口或者虛基類來提供抽象.通過不同的Flag來初始化不同的產品.

總結一句:簡單工廠設計模式就是在一個工廠中實例化出來所有的產品,所以要實例化的對象發生變化的時候,工廠還是要發生變化,所以體驗還是不太好。

public class PhoneGenerator{
    public final static String GENERATE_IOS = "generate_ios";
    public final static String GENERATE_ANDROID = "generate_android";
    public final static String GENERATE_BLACKBERRY = "generate_blackberry";

    public static IPhone generatePhone(String flag) throws Exception {
        IPhone iPhone = null;
        switch (flag){
            case GENERATE_ANDROID:
                iPhone =  new AndroidPhone();
                break;
            case GENERATE_IOS:
                iPhone =  new IosPhone();
                break;
            case GENERATE_BLACKBERRY:
                iPhone =  new BlackBerryPhone();
                break;
            default:
                throw new Exception("UNDEFINED FLAG");
        }
        return iPhone;
    }
}

對外部來說要使用工廠只需要把目標產品類傳過去就行了.運行結果跟1)中的是一樣的.

3)結合反射的應用

假設需要加入一種搭載win10系統的手機,標準的工廠方法模式需要重新派生出來一個新的工廠來給客戶使用,簡單工廠模式也需要新增新的flag和case判斷去構造新的手機.有沒有什麽方法可以盡量避免這些修改呢?當然是有的,這裏可以通過使用Class.forName 反射的方式來達到目的.

首先通過泛型來約束輸入輸出的參數類型,把異常拋到上層去處理並實現具體的工廠.

public abstract class IGenerator {
    public abstract <T extends IPhone>T generatePhone(Class<T> clazz) throws Exception;
}
public class PhoneGenerator extends IGenerator {
    public <T extends IPhone>T generatePhone(Class<T> clazz) throws Exception {
        IPhone iPhone = null;
        iPhone = (IPhone) Class.forName(clazz.getName()).newInstance();
        return (T)iPhone;
    }
}

通過這種裝載的方式去初始化產品就可以達到上面描述的需求,可以根據需求直接添加一個實現了IPhone接口的WindowsPhone產品而不需要修改工廠,客戶就可以直接從工廠拿到WindowsPhone的手機去使用了.

工廠設計模式