設(shè)計(jì)模式-簡單工廠模式

設(shè)計(jì)模式的起源
模式的研究起源于建筑設(shè)計(jì)大師Christopher Alexander的關(guān)于城市規(guī)劃和建筑設(shè)計(jì)的著作。盡管他的著作是針對(duì)城市規(guī)劃和建筑設(shè)計(jì)的,但是作者的觀點(diǎn)實(shí)際上適用于所有工程設(shè)計(jì)領(lǐng)域,包括軟件開發(fā)設(shè)計(jì)領(lǐng)域。

Alexander 在他的著作中指出,「每一個(gè)模式描述了一個(gè)在我們周圍不斷重復(fù)發(fā)生的問題,以及該問題的解決方案的核心。這樣,你就能一次又一次地使用該方案而不必做重復(fù)勞動(dòng)」。盡管Alexander所指的是城市和建筑模式,但他的思想也同樣適用于面向?qū)ο笤O(shè)計(jì)模式,只是在面向?qū)ο蟮慕鉀Q方案里,我們用對(duì)象和接口代替了墻壁和門窗。兩類模式的核心都在于提供了相關(guān)問題的解決方案。

創(chuàng)建模式-為什么使用簡單工廠模式
設(shè)計(jì)模式一般主要分為創(chuàng)建模式、結(jié)構(gòu)模式、行為模式。本文主要講解「創(chuàng)建模式」中的「簡單工廠模式」。

創(chuàng)建模式(Creational Pattern)是對(duì)類的實(shí)例化過程的抽象化。一些系統(tǒng)在創(chuàng)建對(duì)象時(shí),需要?jiǎng)討B(tài)地決定怎樣創(chuàng)建對(duì)象,創(chuàng)建哪些對(duì)象,以及如何組合和表示這些對(duì)象。創(chuàng)建模式描述了怎樣構(gòu)造和封裝這些動(dòng)態(tài)的決定。
創(chuàng)建模式分為類的創(chuàng)建模式和對(duì)象的創(chuàng)建模式兩種。
1.類的創(chuàng)建模式:類的創(chuàng)建模式使用繼承關(guān)系,把類的創(chuàng)建延遲到子類,從而封裝了客戶端將得到哪些具體類的信息,并且隱藏了這些類的實(shí)例是如何創(chuàng)建和放在一起。
2.對(duì)象的創(chuàng)建模式: 對(duì)象的創(chuàng)建模式則把對(duì)象的創(chuàng)建過程動(dòng)態(tài)地委派給另一個(gè)對(duì)象,從而動(dòng)態(tài)地決定客戶端將得到哪些具體類的實(shí)例,以及這些類的實(shí)例是如何被創(chuàng)建和組合在一起的。

創(chuàng)建模式包括:簡單工廠模式、工廠方法模式、抽象工廠模式、單例模式、多例模式、建造模式、原始模型模式等等。

工廠模式的幾種形態(tài)
工廠模式專門負(fù)責(zé)將大量有共同接口的類實(shí)例化。工廠模式可以動(dòng)態(tài)決定將哪一個(gè)類實(shí)例化,不必事先知道每次要實(shí)例化哪一個(gè)類。工廠模式有以下幾種形態(tài):
1.簡單工廠模式(Simple Factory Pattern)
2.工廠方法模式(Factory Method Pattern)
3.抽象工廠模式(Abstract Factory Pattern)

簡單工廠模式,或稱靜態(tài)工廠方法(Static Factory Method)模式。該模式的核心是工廠類,這個(gè)類含有必要的判斷邏輯,可以決定在什么時(shí)候創(chuàng)建哪一個(gè)產(chǎn)品類的實(shí)例。而客戶端則可以免除直接創(chuàng)建產(chǎn)品對(duì)象的責(zé)任,而僅僅負(fù)責(zé)「消費(fèi)」產(chǎn)品。簡單工廠模式通過這種做法實(shí)現(xiàn)了對(duì)責(zé)任的分割。

栗子:
比如說有一家農(nóng)場,向市場銷售各種類型的水果。在農(nóng)場中有種植以下水果:
1.蘋果 Apple
2.葡萄 Grape
3.草莓 Strawberry

水果與其他的植物有很大的不同,水果最終是可以采摘食用的。那么一個(gè)自然的作法就是建立一個(gè)各種水果都適用的接口,以便與農(nóng)場里的其他植物區(qū)分開。


水果接口規(guī)定出所有的水果必須實(shí)現(xiàn)的接口,包括任何水果類必須具備的方法:
1.種植plant()
2.生長grow()
3.收獲harvest()

水果接口源碼:

public interface Fruit {
     //種植
     void plant();
     //生長
     void grow();
     //收獲
     void harvest();
}

Apple類是水果類的一種,因此它實(shí)現(xiàn)了水果接口所聲明的所有方法。另外,由于蘋果是多年生植物,因此多出一個(gè)treeAge性質(zhì),描述蘋果樹的樹齡。
蘋果類的源碼:

public class Apple implements Fruit {
    private int treeAge;
     
    public void plant() {
        System.out.println(“Apple has been planted.”);
    }
     
    public void grow() {
        System.out.println(“Apple is growing.”);
    }
     
    public void harvest() {
        System.out.println(“Apple has been harvested.”);
    }
    
    public int getTreeAge() {
        return treeAge;
    }
    
    public void setTreeAge(int treeAge) {
        this.treeAge = treeAge;
    }
}

同樣,Grape類是水果類的一種,也實(shí)現(xiàn)了Fruit接口所聲明的所有方法。但由于葡萄分為有籽和無籽兩種,因此,比普通水果多出一個(gè)seedless性質(zhì)。
葡萄類的源碼:

public class Grape implements Fruit {
    private boolean seedless;
     
    public void plant() {
        System.out.println(“Grape has been planted.”);
    }
    
    public void grow() {
        System.out.println(“Grape is growing.”);
    }
    
    public void harvest() {
        System.out.println(“Grape has been harvested.”);
    }
    
    public boolean getSeedless() {
        return seedless;
    }
    
    public void setSeedless(boolean seedless) {
        this.seedless = seedless;
    }
}

Strawberry 類實(shí)現(xiàn)了Fruit接口,因此也是水果類型的子類型。
草莓類源碼:

public class Strawberry implements Fruit {
    public void plant() {
        System.out.println(“Grape has been planted.”);
    }
    
    public void grow() {
        System.out.println(“Grape is growing.”);
    }
    
    public void harvest() {
        System.out.println(“Grape has been harvested.”);
    }
}

接下來,我們需要定義一個(gè)工廠類,在我們的栗子中是FruitFactory類。該類中有一個(gè)靜態(tài)的getFruit方法,取決于條件的給予,返回不同的Fruit實(shí)例。

class FruitFactory {
    public static Fruit getFruit(String criteria) {
        if (criteria.equals(“Apple”)) {
            return new Apple();
        } else if (criteria.equals(“Grape")) {
            return new Grape();
        } else if (criteria.equals(“Strawberry”)) {
            return new Strawberry();
        }
        return null;  
    }
}

最后作為消費(fèi)者,僅需調(diào)用FruitFactory的靜態(tài)方法getFruit(),即可以得到可口的水果了。具體代碼如下:

public class FruitConsumer {
    public static void main(String[] args) {
        Fruit fruit = null;
        
        fruit = FruitFactory.getFruit("Apple");
        fruit.harvest();
        
        fruit = FruitFactory.getFruit("Grape");
        fruit.harvest(); 
               
        fruit = FruitFactory.getFruit("Strawberry");
        fruit.harvest();
    }
}

輸出結(jié)果:

Apple has been harvested.
Grape has been harvested.
Strawberry has been harvested.

參考:
「1」Design Patterns: Elements of Reusable Object-Oriented Software
「2」Java 與模式
「3」A Java Factory Pattern example

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

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

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