淺談工廠模式

工廠模式

工廠模式我們分爲兩個方面討論,一個是工廠模式,另外一個是spring中的工廠模式應用。
工廠模式是我們最常用的實例化對象模式了,是用工廠方法代替new操作的一種模式,這裏着重理解下替代new操作,一般來說對象我們需要new Object()去實例化,如果一個對象需要在構造函數中實例化,在實例化之前需要處理一大堆操作和流程,那麼在創建這個對象的時候需要寫一大堆代碼,這樣我們的構造函數看起來就非常的臃腫了,這時候我們想到了工廠模式,我們將實例化的操作交給工廠對象去實現,這樣我們即避免了對客戶端暴露創建邏輯,又避免了將很多雞蛋放在一個籃子裏,儘量將長代碼分成各個段,並將每一段再次封裝起來,這樣更加符合面相對象的開閉原則。
工廠模式分爲 簡單工廠抽象工廠

簡單工廠

簡單工廠中有三個角色(以下面代碼爲例):
工廠角色(CarFatory): 這就是工廠模式的核心,也就是工廠類,負責創建所有產品對象的內部邏輯,他可以用static來修飾,然後外部主程序可以直接調用它內部的方法produce來創建所需要的產品對象,我們看到它的返回參數類型是Car。
抽象產品角色(Car): 它是工廠模式中所有創建的具體對象的父類,可以定義成接口,也可以用抽象類定義,看自己的需求而定。
具體產品角色(ConcreteCar): 它是簡單工廠模式創建的目標對象,可以創建N個繼承於抽象角色對象的具體角色對象,每一個都需要實現抽象對象中的抽象方法,也可以有自己的內部特色實現。
直接看接口和實現:
第一步,先定義一個基礎的抽象接口,用汽車這個做基礎的抽象接口,接口中有一個produce方法,可以讓繼承這個接口的派生類實際對象去實現。

package factory;

public interface Car {
    void carName();
}

第二步,添加多個實現類
新建一個BenzCar繼承Car,並實現produce方法。

package factory;

public class BenzCar implements Car {
    @Override
    public void carName() {
        System.out.println("This is a Benz car");
    }
}

新建一個BMWCar繼承Car,並實現produce方法。

package factory;

public class BMWCar implements Car {
    @Override
    public void carName() {
        System.out.println("This is a BMW car");
    }
}

新建一個BuickCar繼承Car,並實現produce方法。

package factory;

public class BuickCar implements Car {
    @Override
    public void carName() {
        System.out.println("This is a Buick car");
    }
}

第三步,建一個工廠類,用於實例化各個對象。

package factory;

public class CarFatory {

    public static Car produce(String producer) {
        System.out.println("Produce a car");
        if (producer == null) {
            return null;
        }
        switch (producer) {
            case "Benz":
                return new BenzCar();
            case "BMW":
                return new BMWCar();
            case "Buick":
                return new BuickCar();
            default:
                return null;
        }
    }
}

第四步,主程序測試。

package factory;

public class SimpleFactoryTest {
    public static void main(String[] args) {
        Car bmwCar = CarFatory.produce("BMW");
        bmwCar.carName();

        Car benzCar = CarFatory.produce("Benz");
        benzCar.carName();

        Car buickCar = CarFatory.produce("Buick");
        buickCar.carName();
    }
}

第五步,輸出結果

Produce a car
This is a BMW car
Produce a car
This is a Benz car
Produce a car
This is a Buick car

總結,主程序SimpleFactoryTest只需要告訴工廠對象CarFatory它需要什麼樣類型的對象,CarFatory便生產什麼樣的對象,主程序並不關心這個對象的生產過程是什麼樣的,就像我們工作中的領導分配任務,只看最終結果,你們怎麼去實現他Care,簡單工廠看起來就是這樣簡明清晰,各司其職,分工明確,但是 缺點 是如果主程序想再加一個NissanCar,那麼這時就需要再新建一個類繼承Car實現produce方法,並在CarFatory的getCar()方法中實例化NissanCar這個對象,才能返回給主程序使用,這樣的模式違背了開放-封閉原則,具體的產品和工廠之間的耦合度非常高,嚴重影響了系統的靈活性和擴展性,所以我們需要對簡單工廠模式進行進一步抽象,下一步我們來看下抽象工廠

抽象工廠

OK,我們在簡單工廠模式中看到抽象產品Car有不同的實現BenzCar,BMWCar,BuickCar,那麼對於工廠對象CarFatory我們可不可以也做一次抽象,讓CarFactory繼承自一個抽象對象IFactory,IFactory是所有這一類型Car生成商的父類,我們可以根據這個對象派生出DeutschCarFactory,AmericanCarFactory等這幾種ConcreteFactory對象,這樣我們就可以根據不同的產品類型提供不同的工廠,將工廠類的實例化延伸到了子類,這就是所謂的工廠方法模式,由稱爲多態工廠模式。
####工廠模式方法
除了簡單工廠模式中的有四種角色類型,產品角色類型和簡單工廠模式中相同,剩下兩個角色是抽象工廠和真實工廠。
抽象工廠角色(IFactory): 抽象工廠是所有真實工廠類的父類,可以是接口,也可以是抽象類,所有真實角色都需要實現這個類中的抽象方法。
具體工廠角色(ConcreteFactory): 由抽象工廠派生出的子類,可以由客戶端主程序調用返回一個具體的產品。
代碼中,我在這裏新增加兩個真實產品角色,FordCar和CadillacCar用於讓AmericanCarFactory生產這兩個產品,而原有的BMWCar和BenzCar用DeutschCarFactory這個工廠生產。
第一步,增加產品角色FordCar和CadillacCar。

package factory;

public class CadillacCar implements Car {
    @Override
    public void carName() {
        System.out.println("This is a Cadillac car");
    }
}
package factory;

public class FordCar implements Car {
    @Override
    public void carName() {
        System.out.println("This is a Ford car");
    }
}

第二步,增加抽象工廠IFactory

package factory;

public interface IFactory {
    Car produce(String producer);
}

第三步,新建真實工廠DeutschCarFactory和AmericanCarFactory實現IFactory,並重寫父類IFactory中的抽象方法。

package factory;

public class AmericanCarFactory implements IFactory {
    @Override
    public Car produce(String producer) {
        if (producer == null) {
            return null;
        }
        System.out.println("Produce an American car");
        switch (producer) {
            case "Ford":
                return new BenzCar();
            case "Cadillac":
                return new BuickCar();
            default:
                return null;
        }
    }
}
package factory;

public class DeutschCarFactory implements IFactory {
    @Override
    public Car produce(String producer) {
        if (producer == null) {
            return null;
        }
        System.out.println("Produce an Deutsch car");
        switch (producer) {
            case "Benz":
                return new BenzCar();
            case "BMW":
                return new BMWCar();
            default:
                return null;
        }
    }
}

在實際使用中,真實工廠還需要處理一些產品的初始化,數據庫連接等操作。
第四步,編寫測試代碼FactoryMethodTest。

package factory;

public class FactoryMethodTest {
    public static void main(String[] args) {
        DeutschCarFactory deutschCarFactory = new DeutschCarFactory();
        Car bmwCar = deutschCarFactory.produce("BMW");
        bmwCar.carName();
        Car benzCar = deutschCarFactory.produce("Benz");
        benzCar.carName();

        System.out.println("------------------------");
        AmericanCarFactory americanCarFactory = new AmericanCarFactory();
        Car fordCar = americanCarFactory.produce("Ford");
        fordCar.carName();
        Car cadillacCar = americanCarFactory.produce("Cadillac");
        cadillacCar.carName();
    }
}

看下輸出:

Produce an Deutsch car
This is a BMW car
Produce an Deutsch car
This is a Benz car
------------------------
Produce an American car
This is a Ford car
Produce an American car
This is a Cadillac car

可以看到各個工廠各司其職,生產了各自的屬性的產品。和簡單工廠模式相比,我們如果需要生產大衆車,也是德系車,那麼我們只需要新增一個VolkswagenCar繼承Car,DeutschCarFactory新增VolkswagenCar的初始化實例即可,這樣的改動不會影響到AmericanCarFactory這裏的任何信息,極大的改善了簡單工廠模式違背開閉原則的缺點。如果需要新生產日系車,那我們需要新增一個日系車的工廠JapaneseCarFactory繼承IFactory實現其中的抽象方法,並寫好各個車型的對象需要繼承基類Car,然後由客戶端調用即可。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章