工廠模式02之工廠方法模式

參考:Head First設(shè)計模式

概述

  • 簡單工廠模式實現(xiàn)了生成產(chǎn)品類的代碼與客戶端代碼分離,在工廠類中可以添加生成產(chǎn)品的邏輯代碼。

  • 但是簡單工廠模式不符合“開放-封閉”原則。例如要加一個 新產(chǎn)品類,就要修改 工廠類 生成產(chǎn)品的邏輯代碼,增加if-else判斷。對于這個問題,工廠方法模式可以解決。

定義

工廠方法模式 定義了一個創(chuàng)建對象的接口,但由子類決定要實例化的類是哪一個。工廠方法模式 讓類把實例化推遲到子類。

類圖

  • 角色
  1. 抽象產(chǎn)品類 : Product
  2. 具體產(chǎn)品類 : ConcreteProductA 和 ConcreteProductB
  3. 抽象工廠類 : AbstractFactory
  4. 具體工廠類 : ConcreteFactoryA 和 ConcreteFactoryB

實例

還是以披薩店的披薩訂單為例,用工廠方法模式來處理披薩店的訂單。并且披薩店還開了加盟店,有紐約披薩店芝加哥披薩店。

類圖

  • 創(chuàng)建者類(抽象工廠類 + 具體工廠實現(xiàn)類)
  • 產(chǎn)品類(抽象產(chǎn)品類 + 具體產(chǎn)品實現(xiàn)類)

代碼實現(xiàn)

  • 抽象工廠類PizzaStore
package cn.edu.nwpu.factoryMethod;
/**
 * 
 * @author yylin
 *
 */
public abstract class PizzaStore {

    public Pizza orderPizza(String type) {
        Pizza pizza = null;
        
        pizza = createPizza(type);
        
        pizza.prepare();
        pizza.bake();
        pizza.cut();
        pizza.box();
        
        return pizza;
    }

    // 抽象的工廠方法
    abstract Pizza createPizza(String type);
}
  • 具體工廠實現(xiàn)類1 NYPizzaStore
package cn.edu.nwpu.factoryMethod;
/**
 * 
 * @author yylin
 *
 */
public class NYStylePizzaStore extends PizzaStore {

    @Override
    Pizza createPizza(String type) {

        Pizza pizza = null;
        
        if(type.equals("cheese")) {
            pizza = new NYStyleCheesePizza();
        } else if(type.equals("prpperoni")) {
            pizza = new NYStylePepperoniPizza();
        } else if(type.equals("clam")) {
            pizza = new NYStyleClamPizza();
        } else if(type.equals("veggie")) {
            pizza = new NYStyleVeggiePizza();
        }
        
        return pizza;
    }

}
  • 具體工廠實現(xiàn)類2 ChicagoPizzaStore
package cn.edu.nwpu.factoryMethod;
/**
 * 
 * @author yylin
 *
 */
public class ChicagoStylePizzaStore extends PizzaStore {

    @Override
    Pizza createPizza(String type) {

        Pizza pizza = null;
        
        if(type.equals("cheese")) {
            pizza = new ChicagoStyleCheesePizza();
        } else if(type.equals("prpperoni")) {
            pizza = new ChicagoStylePepperoniPizza();
        } else if(type.equals("clam")) {
            pizza = new ChicagoStyleClamPizza();
        } else if(type.equals("veggie")) {
            pizza = new ChicagoStyleVeggiePizza();
        }
        
        return pizza;
    }

}
  • 抽象產(chǎn)品類Pizza
package cn.edu.nwpu.factoryMethod;

import java.util.ArrayList;

/**
 * 
 * @author yylin
 *
 */
public abstract class Pizza {
    /*
     * 抽象類提供了默認(rèn)基本做法, 準(zhǔn)備工作以特定順序進(jìn)行
     */
    String name;
    String dough;
    String sauce;
    ArrayList toppings = new ArrayList();

    public void prepare() {
        System.out.println("Preparing " + name);
        System.out.println("Tossing dough...");
        System.out.println("Adding sauce...");
        System.out.println("Adding toppings: ");
        for (int i = 0; i < toppings.size(); i++) {
            System.out.println("   " + toppings.get(i));
        }
    }

    public void bake() {
        System.out.println("Bake for 25 minutes at 350");
    }

    public void cut() {
        System.out.println("Cutting the pizza into diagonal slices");
    }

    public void box() {
        System.out.println("Place pizza in official PizzaStore box");
    }

    public String getName() {
        return name;
    }
}
  • 具體產(chǎn)品實現(xiàn)類1 NYStyleCheesePizza
package cn.edu.nwpu.factoryMethod;
/**
 * 
 * @author yylin
 *
 */
public class NYStyleCheesePizza extends Pizza {

    /*
     * 具體產(chǎn)品實現(xiàn)類中可以加入自己的特色,或者覆蓋Pizza類中的方法
     */
    public NYStyleCheesePizza(){
        name = "NY Style Sauce and Cheese Pizza";
        dough = "Thin Crust Dough";
        sauce = "Marinara Sauce";
        
        toppings.add("Grated Reggiano Cheese");
    }
}
  • 具體產(chǎn)品實現(xiàn)類2 NYStylePepperoniPizza
package cn.edu.nwpu.factoryMethod;
/**
 * 
 * @author yylin
 *
 */
public class NYStylePepperoniPizza extends Pizza {

}
  • 具體產(chǎn)品實現(xiàn)類3 NYStyleClamPizza
package cn.edu.nwpu.factoryMethod;
/**
 * 
 * @author yylin
 *
 */
public class NYStyleClamPizza extends Pizza {

}
  • 具體產(chǎn)品實現(xiàn)類4 NYStyleVeggiePizza
package cn.edu.nwpu.factoryMethod;
/**
 * 
 * @author yylin
 *
 */
public class NYStyleVeggiePizza extends Pizza {

}
  • 具體產(chǎn)品實現(xiàn)類5 ChicagoStyleCheesePizza
package cn.edu.nwpu.factoryMethod;

/**
 * 
 * @author yylin
 *
 */
public class ChicagoStyleCheesePizza extends Pizza {

    /*
     * 具體產(chǎn)品實現(xiàn)類中可以加入自己的特色,或者覆蓋Pizza類中的方法
     */
    public ChicagoStyleCheesePizza() {
        name = "";
        dough = "";
        sauce = "";

        toppings.add("");
    }

    @Override
    public void cut() {
        System.out.println("Cutting the pizza into square slices");
    }
}
  • 具體產(chǎn)品實現(xiàn)類6 ChicagoStylePepperoniPizza
package cn.edu.nwpu.factoryMethod;
/**
 * 
 * @author yylin
 *
 */
public class ChicagoStylePepperoniPizza extends Pizza {

}
  • 具體產(chǎn)品實現(xiàn)類7 ChicagoStyleClamPizza
package cn.edu.nwpu.factoryMethod;
/**
 * 
 * @author yylin
 *
 */
public class ChicagoStyleClamPizza extends Pizza {

}
  • 具體產(chǎn)品實現(xiàn)類8 ChicagoStyleVeggiePizza
package cn.edu.nwpu.factoryMethod;
/**
 * 
 * @author yylin
 *
 */
public class ChicagoStyleVeggiePizza extends Pizza {

}
  • 測試類 PizzaTestDrive

顧客Ethan想要紐約風(fēng)格的奶酪披薩,顧客Joel想要芝加哥風(fēng)格的奶酪披薩。

package cn.edu.nwpu.factoryMethod;
/**
 * 
 * @author yylin
 *
 */
public class PizzaTestDrive {

    public static void main(String[] args) {

        // 建立兩個不同的披薩店
        PizzaStore nyStore = new NYStylePizzaStore();
        PizzaStore chicagoStore = new ChicagoStylePizzaStore();

        // 顧客Ethan的訂單
        Pizza pizza = nyStore.orderPizza("cheese");
        System.out.println("Ethan ordered a " + pizza.getName() + "\n");
        
        // 顧客Joel的訂單
        pizza = chicagoStore.orderPizza("cheese");
        System.out.println("Joel ordered a " + pizza.getName() + "\n");
    }
}
  • 測試結(jié)果
Preparing NY Style Sauce and Cheese Pizza
Tossing dough...
Adding sauce...
Adding toppings: 
   Grated Reggiano Cheese
Bake for 25 minutes at 350
Cutting the pizza into diagonal slices
Place pizza in official PizzaStore box
Ethan ordered a NY Style Sauce and Cheese Pizza

Preparing Chicago Style Deep Dish Cheese Pizza
Tossing dough...
Adding sauce...
Adding toppings: 
   Shredded Mozzarella Cheese
Bake for 25 minutes at 350
Cutting the pizza into square slices
Place pizza in official PizzaStore box
Joel ordered a Chicago Style Deep Dish Cheese Pizza

小結(jié)

  1. 工廠方法模式又稱為工廠模式,也叫虛擬構(gòu)造器(Virtual Constructor)模式或者多態(tài)工廠模式(Polymorphic Factory)。

  2. 在工廠方法模式中,父類負(fù)責(zé)定義創(chuàng)建對象的公共接口,而子類則負(fù)責(zé)生成具體的對象;
    這樣做的目的是將類的實例化操作延遲到子類中完成;
    即由子類來決定究竟應(yīng)該實例化(創(chuàng)建)哪一個類。

  3. 工廠方法模式包含四個角色:
    (1)抽象產(chǎn)品是定義產(chǎn)品的接口,是工廠方法模式所創(chuàng)建對象的超類型,即產(chǎn)品對象的共同父類或接口;
    (2)具體產(chǎn)品實現(xiàn)了抽象產(chǎn)品接口,某種類型的具體產(chǎn)品由專門的具體工廠創(chuàng)建,它們之間往往一一對應(yīng);
    (3)抽象工廠中聲明了工廠方法,用于返回一個產(chǎn)品,它是工廠方法模式的核心,任何在模式中創(chuàng)建對象的工廠類都必須實現(xiàn)該接口;
    (4)具體工廠是抽象工廠類的子類,實現(xiàn)了抽象工廠中定義的工廠方法,并可由客戶調(diào)用,返回一個具體產(chǎn)品類的實例。

  4. 工廠方法模式是簡單工廠模式的進(jìn)一步抽象和推廣。
    由于使用了面向?qū)ο蟮亩鄳B(tài)性,工廠方法模式保持了簡單工廠模式的優(yōu)點,而且克服了它的缺點。
    在工廠方法模式中,核心的工廠類不再負(fù)責(zé)所有產(chǎn)品的創(chuàng)建,而是將具體創(chuàng)建工作交給子類去做。
    這個核心類僅僅負(fù)責(zé)給出具體工廠必須實現(xiàn)的接口,而不負(fù)責(zé)產(chǎn)品類被實例化這種細(xì)節(jié),這使得工廠方法模式可以允許系統(tǒng)在不修改工廠角色的情況下引進(jìn)新產(chǎn)品。

  5. 工廠方法模式:
    (1)主要優(yōu)點:增加新的產(chǎn)品類時無須修改現(xiàn)有系統(tǒng),并封裝了產(chǎn)品對象的創(chuàng)建細(xì)節(jié),系統(tǒng)具有良好的靈活性和可擴(kuò)展性;
    (2)缺點在于增加新產(chǎn)品的同時需要增加新的工廠,導(dǎo)致系統(tǒng)類的個數(shù)成對增加,在一定程度上增加了系統(tǒng)的復(fù)雜性。

  6. 工廠方法模式適用情況包括:
    (1)一個類不知道它所需要的對象的類;
    (2)一個類通過其子類來指定創(chuàng)建哪個對象;
    (3)將創(chuàng)建對象的任務(wù)委托給多個工廠子類中的某一個,客戶端在使用時可以無須關(guān)心是哪一個工廠子類創(chuàng)建產(chǎn)品子類,需要時再動態(tài)指定。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 設(shè)計模式概述 在學(xué)習(xí)面向?qū)ο笃叽笤O(shè)計原則時需要注意以下幾點:a) 高內(nèi)聚、低耦合和單一職能的“沖突”實際上,這兩者...
    彥幀閱讀 3,888評論 0 14
  • 設(shè)計模式匯總 一、基礎(chǔ)知識 1. 設(shè)計模式概述 定義:設(shè)計模式(Design Pattern)是一套被反復(fù)使用、多...
    MinoyJet閱讀 4,093評論 1 15
  • 該文章屬于劉小壯原創(chuàng),轉(zhuǎn)載請注明:劉小壯[http://www.itdecent.cn/u/2de707c93d...
    劉小壯閱讀 13,034評論 29 59
  • 除了使用new操作符之外,還有更多制造對象的方法。你講了解到實例化這個活動不應(yīng)該總是公開的進(jìn)行,也會認(rèn)識到初始化經(jīng)...
    pilipalaKing閱讀 439評論 0 0
  • 第一章 制定教學(xué)目標(biāo)的策略 策略一 :把握教學(xué)方向 《義務(wù)教育數(shù)學(xué)課程標(biāo)準(zhǔn)》(20111年版)明確提出要通過...
    平常心666閱讀 1,760評論 0 1

友情鏈接更多精彩內(nèi)容