天天看點

淺談設計模式——工廠模式

基本概念

  工廠顧名思義就是建立産品,根據産品是具體産品還是具體工廠可分為簡單工廠模式和工廠方法模式,根據工廠的抽象程度可分為工廠方法模式和抽象工廠模式。

  該模式用于封裝和管理對象的建立,是一種建立型模式。

工廠模式一般分為3類:

  ① 簡單工廠模式(Simple Factory)

  ② 工廠方法模式(Factory Method)

  ③ 抽象工廠模式(Abstract Factory)

  這三個模式從前到後,依次逐漸抽象化。

簡單工廠模式

概述

  這是工廠模式中最簡單的一種,專門定義一個類來負責建立其他類的執行個體,同時被建立的執行個體具有共同的父類。

簡單工廠模式包括3個主要的角色:

  ➷ 簡單工廠類(SimpleFactory):隻包含建立産品的靜态方法。

  ➷ 抽象産品父類(Product):簡單工廠類中生産的産品接口,聲明了産品的抽象方法。

  ➷ 具體産品子類(ProductA 或ProductB):具體産品的實作。

UML圖

淺談設計模式——工廠模式

場景描述

  某城市氣候宜人,盛産水果,尤其盛産蘋果(Apple)和香蕉(Banana),很多年來,各家果農都是自己負責蘋果或香蕉的采摘、包裝、銷售,每個果農都要自備生産包裝的裝置,大家不能複用這些裝置産出水果,是以生産效率非常低下。

  有一個老總看到這個情況,決定投資建立了一家水果工廠(SimpleFactory),統一負責生産這些蘋果或香蕉(Product),各家果農隻要負責提供自己的蘋果(ProductA)或者香蕉(ProductB),工廠負責根據果農的指定生産具體的水果(采摘、包裝、銷售等),是以生産流程效率大大提高,這就是簡單工廠模式。

場景角色映射:

  ★ 簡單工廠類:SimpleFactory→FruitFactory。

  類 FruitFactory 對應 SimpleFactory,它用來統一生産蘋果或香蕉(包裝、銷售等),工廠中有一個靜态方法CreateFruit(),就相當于一套流水線裝置,可以根據提供的水果類型來生産不同的水果(Apple 或者 Banana)。

  ★ 抽象産品父類:Product→Fruit。

  水果接口類,統一定義蘋果類和香蕉類的處理方法。

  ★具體産品子類(ProductA或ProductB):ProductA→Apple,ProductB→Banana。

代碼示範

抽象産品父類

package com.design;

// 抽象産品父類
abstract class Fruit {
    // 構造方法
    public Fruit(){
        System.out.println("生産原料準備中。。");
    };
    // 定義水果的處理方法
    public abstract void operateFruit();
}      

ProductA(Apple)

package com.design;

// 産品A
public class Apple extends Fruit{

    @Override
    public void operateFruit() {
        // 蘋果的生産過程
        System.out.println("開始生産");
        System.out.println("蘋果:生産中。。。");
        System.out.println("蘋果:加工中。。。");
        System.out.println("蘋果:包裝中。。。");
        System.out.println("生産結束");
        System.out.println("這是一個蘋果");
    }

}      

ProductB(Banana)

package com.design;

// 産品B
public class Banana extends Fruit{

    @Override
    public void operateFruit() {
        // 香蕉的生産過程
        System.out.println("開始生産");
        System.out.println("香蕉:生産中。。。");
        System.out.println("香蕉:加工中。。。");
        System.out.println("香蕉:包裝中。。。");
        System.out.println("生産結束");
        System.out.println("這是一個香蕉");
    }

}      

簡單工廠類

package com.design;

// 簡單工廠類
public class FruitFactory {
    // 水果生産裝置
    public static Fruit createFruit(String type) {
        Fruit fruit = null;
        if ("A".equals(type)) {
            fruit = new Apple();
        }else if ("B".equals(type)) {
            fruit = new Banana();
        }
        return fruit;
    }
}      

測試:

package com.design;

public class TestFactory {

    public static void main(String[] args) {
        // 建立工廠
        FruitFactory factory = new FruitFactory();
        
        // 1.生産蘋果
        Fruit apple = factory.createFruit("A");
        apple.operateFruit();
        
        System.out.println("------------------------------------");
        
        // 2.生産香蕉
        Fruit banana = factory.createFruit("A");
        banana.operateFruit();
    }
}      

運作結果:

淺談設計模式——工廠模式

  簡單工廠模式會專門建立一個工廠類FruitFactory,并用一個方法createFruit()根據傳遞參數的不同建立不同類型的執行個體。

  這裡要注意一點,在FruitFactory 中建立對象的類型可以不同(可以是蘋果或者香蕉),但都應當屬于同一個父類(抽象産品父類Fruit)的子類。

  類FruitFactory 就是一個簡單的工廠,将建立對象(蘋果或香蕉)的工作單獨負責下來,使得外界調用統一的方法 createFruit()即可完成不同對象建立(生産蘋果或香蕉)。

工廠方法模式

概述

  工廠方法模式是對簡單工廠模式的改進,它去掉了簡單工廠模式中工廠方法(例如,createFruit()這個方法)的靜态屬性,使得該方法能夠被子類繼承,将簡單工廠模式中在靜态工廠方法中集中建立對象的操作轉移到各子類中完成,進而減輕了父類方法的負擔。

工廠方法模式包括4個主要的角色:

  ➷ 抽象工廠類(AbstractFactory):工廠方法模式的核心,是具體工廠類必須實作的接口或者必須繼承的抽象父類。

  ➷ 具體工廠類(ConcreteFactoryA 或者 ConcreteFactoryB):由具體的類來實作,用于建立工廠類的對象,它必須實作抽象工廠的方法。

  ➷ 抽象産品類(Product):具體産品繼承的抽象父類或者實作的接口,定義了産品類的方法。

  ➷ 具體産品類(ProductA 或ProductB):具體工廠類産生的對象就是具體産品類的對象。

UML圖

淺談設計模式——工廠模式

場景描述

  接上文,随着生産規模的不斷擴大,一個工廠一套裝置生産蘋果和香蕉已經不能滿足公司的業務需求,是以公司的銷售給老總建議,如果把蘋果和香蕉的生産線分開生産效率會更高。原因有兩點:一是兩條生産線互不幹擾進度,二是将來可友善增補其他水果的生産線進而擴充業務。

  于是老總将原來的水果工廠進一步抽象整合,成立了一個水果公司集團(AbstractFactory),集團管理兩家工廠,一家蘋果廠(ConcreteFactoryA),一家香蕉廠(ConcreteFactoryB),集團隻制定統一的規章制度,由這兩家廠具體生産産品,一家生産蘋果,一家生産香蕉,這就是工廠方法模式。

場景角色映射

  ★ 抽象工廠:AbstractFactory→FruitCompany。

  FruitCompany 類是執行個體中描述的水果公司類,該類相當于工廠方法模式中的抽象工廠AbstractFactory,它隻用來制定規章制度(生産水果的方法),實際的生産都交給下面的具體工廠去做。

  ★ 具體工廠:ConcreteFactoryA→AppleFactory,ConcreteFactoryB→BananaFactory。

  AppleFactory 類和 BananaFactory 類分别表示蘋果工廠類和香蕉工廠類,它們都要繼承自抽象工廠類FruitCompany,蘋果工廠按照水果公司的要求生産蘋果;香蕉工廠按照水果公司的要求生産香蕉。

  ★ 抽象産品:Product→Fruit。

  水果接口類,統一定義蘋果和香蕉的處理方法。

  ★ 具體産品:ProductA→Apple,ProductB→Banana。

代碼示範

抽象産品父類

package com.design;

// 抽象産品父類
abstract class Fruit {
    // 構造方法
    public Fruit(){
        System.out.println("生産原料準備中。。");
    };
    // 定義水果的處理方法
    public abstract void operateFruit();
}      

ProductA(Apple)

package com.design;

// 産品A
public class Apple extends Fruit{

    @Override
    public void operateFruit() {
        // 蘋果的生産過程
        System.out.println("開始生産");
        System.out.println("蘋果:生産中。。。");
        System.out.println("蘋果:加工中。。。");
        System.out.println("蘋果:包裝中。。。");
        System.out.println("生産結束");
        System.out.println("這是一個蘋果");
    }

}      

ProductB(Banana)

package com.design;

// 産品B
public class Banana extends Fruit{

    @Override
    public void operateFruit() {
        // 香蕉的生産過程
        System.out.println("開始生産");
        System.out.println("香蕉:生産中。。。");
        System.out.println("香蕉:加工中。。。");
        System.out.println("香蕉:包裝中。。。");
        System.out.println("生産結束");
        System.out.println("這是一個香蕉");
    }

}      

抽象工廠類

package com.design;

// 抽象工廠類
abstract class FruitCompany {
    
    // 聲明一個統一的水果生産方法
    public abstract Fruit createFruit();
}      

具體工廠A(AppleFactory)

package com.design;

// 蘋果工廠
public class AppleFactory extends FruitCompany{

    @Override
    public Fruit createFruit() {
        Fruit fruit = new Apple();
        return fruit;
    }

}      

具體工廠B(BananaFactory)

package com.design;

// 香蕉工廠
public class BananaFactory extends FruitCompany{

    @Override
    public Fruit createFruit() {
        Fruit fruit = new Banana();
        return fruit;
    }

}      

測試:

package com.design;

public class TestFactory {

    public static void main(String[] args) {
        // 建立工廠
        FruitCompany factoryA = new AppleFactory();
        FruitCompany factoryB = new BananaFactory();
        
        // 1.生産蘋果
        Fruit apple = factoryA.createFruit();
        apple.operateFruit();
        
        System.out.println("------------------------------------");
        
        // 2.生産香蕉
        Fruit banana = factoryB.createFruit();
        banana.operateFruit();
    }
}      

運作結果:

淺談設計模式——工廠模式

  工廠方法模式對簡單工廠模式進行了改進,不是用一個工廠類來生産對象,而是用不同的具體工廠子類 AppleFactory 或 BananaFactory來生産不同的對象。

抽象工廠模式 

概述

  抽象工廠模式又是工廠方法模式的更新版本。它的主要思想:提供了一個建立一系列相關或者互相依賴對象的接口。

  它和工廠方法模式的差別:抽象工廠模式針對的是有多個産品(稱為産品族)的建立模式(蘋果廠生産蘋果、蘋果脯;香蕉廠生産香蕉、香蕉幹);而工廠方法針對的隻是一種産品的建立模式(蘋果廠生産蘋果;香蕉廠生産香蕉)。抽象工廠模式中的抽象工廠接口裡有多個工廠方法。

抽象工廠模式包括以下主要角色:

  ➷ 抽象工廠類(AbstractFactory):模式的核心,是具體工廠類必須實作的接口或者必須繼承的抽象父類。

  ➷ 具體工廠類(ConcreteFactoryA 或者 ConcreteFactoryB):由具體的類來實作,用于建立工廠類的對象,它必須實作抽象工廠的方法。

  ➷ 抽象産品(AbstractProductA和AbstractProductB):具體産品繼承的父類或者實作的接口,在Java中由抽象類或者接口實作。

  ➷ 具體産品(ProductA*或ProductB*):具體工廠類産生的對象就是具體産品類的對象。每一個抽象産品都可以有多個具體産品實作類或者繼承子類,稱為産品族。

UML圖

淺談設計模式——工廠模式

場景描述

  接上文,水果公司集團的經營良好,發展規模越來越大,集團全方位發展,産品也開始不再單一,而是向多個産品線(産品族)發展。原來的蘋果廠不再單一地生産蘋果,它開始生産蘋果脯等深加工産品。香蕉廠也同樣生産香蕉幹等産品,這就形成了所謂的抽象工廠模式。

場景角色映射

  ★ 抽象工廠類:AbstractFactory→FruitGroup。

  成立一個水果集團(FruitGroup),該集團就相當于工廠方法模式中的抽象工廠,它的作用隻用來制定規章制度(生産水果的方法),實際的生産都交給下面的具體工廠去做,下屬多個工廠,有蘋果廠、香蕉廠等。

  ★ 具體工廠類:ConcreteFactoryA→AppleFactory;Concrete FactoryB→BananaFactory。

  AppleFactory 類和 BananaFactory 類分别表示蘋果工廠類和香蕉工廠類,它們都要實作抽象工廠FruitGroup,蘋果工廠按照水果集團的要求生産蘋果及蘋果脯;香蕉工廠生産按照水果集團的要求生産香蕉和香蕉幹。

  ★ 抽象産品類:AbstractProductA→Fruit;AbstractProductB→DriedFruit。

  Furit 類和 DriedFruit類分别為水果和水果脯類的抽象父類,具體産品類要繼承這兩個類。

  ★ 具體産品:ProductA1→Apple,ProductA2→Banana;ProductB1→DriedApple,ProductB2→DriedBanana。

代碼示範

抽象産品類(Fruit)

package com.design;

// 抽象Fruit産品父類
abstract class Fruit {
    // 構造方法
    public Fruit(){
        System.out.println("生産原料準備中。。");
    };
    // 定義水果的處理方法
    public abstract void operateFruit();
}      

具體産品(Apple)

package com.design;

// Fruit産品A
public class Apple extends Fruit{

    @Override
    public void operateFruit() {
        // 蘋果的生産過程
        System.out.println("開始生産");
        System.out.println("蘋果:生産中。。。");
        System.out.println("蘋果:加工中。。。");
        System.out.println("蘋果:包裝中。。。");
        System.out.println("生産結束");
        System.out.println("這是一個蘋果");
    }

}      

具體産品(Banana)

package com.design;

// Fruit産品B
public class Banana extends Fruit{

    @Override
    public void operateFruit() {
        // 香蕉的生産過程
        System.out.println("開始生産");
        System.out.println("香蕉:生産中。。。");
        System.out.println("香蕉:加工中。。。");
        System.out.println("香蕉:包裝中。。。");
        System.out.println("生産結束");
        System.out.println("這是一個香蕉");
    }

}      

抽象産品類(DriedFruit)

package com.design;

// 抽象果脯産品父類
abstract class DriedFruit {

    // 果脯生産方法
    public abstract void operateProduct();
}      

具體産品(DriedApple)

package com.design;

// 蘋果幹
public class DriedApple extends DriedFruit{

    @Override
    public void operateProduct() {
        System.out.println("生産了一個蘋果幹");
    }

}      

具體産品(DriedBanana)

package com.design;

// 香蕉幹
public class DriedBanana extends DriedFruit{

    @Override
    public void operateProduct() {
        System.out.println("生産了一個香蕉幹");
    }

}      

抽象工廠類

package com.design;

// 抽象工廠類,水果集團:生産水果和果脯。
abstract class FruitGroup {

    // 生産水果
    public abstract Fruit createFruit();
    // 生産果脯
    public abstract DriedFruit createDriedFruit();
    
}      

具體工廠類(AppleFactory)

package com.design;

// 蘋果工廠
public class AppleFactory extends FruitGroup{

    @Override
    public Fruit createFruit() {
        Fruit fruit = new Apple();
        return fruit;
    }

    @Override
    public DriedFruit createDriedFruit() {
        DriedFruit driedFruit = new DriedApple();
        return driedFruit;
    }

}      

具體工廠類(BananaFactory)

package com.design;

// 香蕉工廠
public class BananaFactory extends FruitGroup{

    @Override
    public Fruit createFruit() {
        Fruit fruit = new Banana();
        return fruit;
    }

    @Override
    public DriedFruit createDriedFruit() {
        DriedFruit driedFruit = new DriedBanana();
        return driedFruit;
    }
    

}      

測試:

package com.design;

public class TestFactory {

    public static void main(String[] args) {
        // 建立工廠
        FruitGroup factoryA = new AppleFactory();
        FruitGroup factoryB = new BananaFactory();
        
        // 1.生産蘋果
        Fruit apple = factoryA.createFruit();
        apple.operateFruit();
        
        // 生産蘋果幹
        DriedFruit driedApple = factoryA.createDriedFruit();
        driedApple.operateProduct();
        
        System.out.println("------------------------------------");
        
        // 2.生産香蕉
        Fruit banana = factoryB.createFruit();
        banana.operateFruit();
        
        // 生産香蕉幹
        DriedFruit driedBanana = factoryA.createDriedFruit();
        driedBanana.operateProduct();
        
    }
}      

運作結果:

淺談設計模式——工廠模式

  抽象工廠是一個超級工廠,它生産了多種産品而不隻是一種産品(例如,蘋果工廠既可以生産蘋果也可以生産蘋果脯),是以它解決了工廠方法模式下一個工廠隻能生産一種産品的局限問題。

  抽象工廠模式隔離了具體類的生成,所有的具體工廠都實作了抽象工廠中定義的公共接口,是以隻需要改變具體工廠的代碼,就能改變某個工廠的行為。

工廠模式總結

  工廠模式,顧名思義就是生産對象的。

根據其抽象程度可分為以下三種:

簡單工廠模式

  一個工廠(具體工廠),生産多種産品,根據所傳類型,生産相應的産品。

➷ 優點:

  簡單工廠類功能統一,使得外界從建立具體對象中分離出來,不用負責具體建立哪個類的對象,隻要調用方法,由簡單工廠統一建立即可。

➷ 缺點:

  簡單工廠類中集中了所有要建立的對象,如果需要添加新的建立對象類型,就必須改變簡單工廠類的代碼,這将違背開放封閉原則。這種情況在工廠方法模式中得到了部分解決。

工廠方法模式

  一個公司(抽象工廠),生産多種産品,公司下面有多個工廠(具體工廠),每個工廠隻生産一種産品。

➷ 優點:

  解決了簡單工廠模式中靜态工廠方法在新增對象類型分支時需要修改方法代碼的問題。在工廠方法模式中新增對象類型隻需新增代碼即可,不需要修改已有的代碼,這樣遵循了開放封閉原則,即對擴充開放,對修改封閉的原則。

➷ 缺點:

  每增加一個産品類型,相應地也要增加一個子工廠,加大了額外的開發量。

抽象工廠模式

  一個集團(抽象工廠),生産多個産品族的産品,集團下面有多個工廠(具體工廠),每個工廠隻生産一個産品族的多種産品。

➷ 優點:

  抽象工廠模式既具有工廠方法模式的上述優點,同時又解決了工廠方法模式一個具體工廠隻能建立一類産品的局限,抽象工廠模式中每個工廠可以建立多種類型的産品(産品族)。同時,如果需要生産新的産品(不新增産品族),隻需要擴充該産品對應的具體工廠和該産品的具體實作類,不需要改變抽象工廠類和抽象産品類。 

➷ 缺點:

  抽象工廠最大的缺點是産品族難以擴充。假如産品族中需要增加一個新的産品,則幾乎所有的工廠類都需要進行修改。是以使用抽象工廠模式時對産品等級結構的劃分是非常重要的。

繼續閱讀