設計模式——簡單工廠模式

爆米花9958發表於2017-02-24
概述
簡單工廠模式(Simple Factory Pattern)是通過專門定義一個工廠類來負責建立其他類的例項,被建立的例項通常都具有共同的父類。它可以根據引數的不同返回不同類的例項,而無須知道其建立細節。如果在簡單工廠模式中用於建立例項的方法是靜態(static)方法,則被稱為靜態工廠方法(Static Factory Method)模式,它不屬於23種設計模式,但在軟體開發中應用也較為頻繁,通常將它作為學習其他工廠模式的入門。其實工廠模式分為了最弱的簡單工廠模式,工廠方法模式,牛逼的抽象工廠模式。
簡單工廠模式結構中包括三種角色:
  • 工廠類(Factory):它是簡單工廠模式的核心,負責實現建立所有產品例項的內部邏輯;工廠類可以被外界直接呼叫,建立所需的產品物件;在工廠類中提供了靜態的工廠方法,返回型別為抽象產品型別。
  • 抽象產品(Product):工廠類所建立的所有物件的父類,封裝了各種產品物件的公有方法,它的引入將提高系統的靈活性,使得在工廠類中只需定義一個通用的工廠方法,因為所有建立的具體產品物件都是其子類物件。
  • 具體產品(ConcreteProduct):簡單工廠模式的建立目標,所有被建立的物件都充當這個角色的某個具體類的例項。每一個具體產品角色都繼承了抽象產品角色,需要實現在抽象產品中宣告的抽象方法。
例項應用
從我的一次面試經歷說起,猶記得當年剛畢業時懷揣著要用程式碼拯救世界的夢想,結果現實是無情的,一次次求職碰壁,才發現自己圖樣圖森破,唉,“滿紙荒唐言,一把辛酸淚”,就把我的經歷分享給初出茅廬的學弟們以做警戒吧,面試官給我出了個題目,要求利用一種物件導向的語言實現一個簡單的計算器程式,我心想這不很簡單嗎,馬上就把程式碼寫出來,如下:
Scanner scanner=new Scanner(System.in);

System.out.println("請輸入第一個數");
double numA=scanner.nextDouble();
System.out.println("請輸入第二個數");
double numB=scanner.nextDouble();
System.out.println("請輸入運算子");
String operate=scanner.next();

double result=0;
switch (operate){
    case "+":
        result=numA+numB;
        break;
    case "-":
        result=numA-numB;
        break;
    case "*":
        result=numA*numB;
        break;
    case "/":
        result=numA/numB;
        break;
}
System.out.println("最後結果為:"+result);
哈哈,自我感覺良好啊,然後面試官看了看,讓我回去等訊息,然後就沒有然後了。。。多年後我才發現,當時是多麼幼稚,看一下程式碼,先不說具體的異常處理問題,先說題目的要求——用一種物件導向的語言!我這寫的完全是程式導向的程式碼。。。唉,都怨C語言學的太好了,呃~
很多物件導向程式設計的初學者都會有這樣的問題,那就是遇到問題就直覺的用計算機的方式去思考,這樣的思維雖然可以解決問題,但卻使得我們的程式只滿足當前的需求,程式不容易維護,不容易擴充套件,更不容易複用。既然認識到問題了,那我們就亡羊補牢吧,下面是我的修改版:
public double getResult(double numberA, double numberB, char operate) {
    double result = 0d;
    switch (operate) {
        case '+':
            result = numberA + numberB;
            break;
        case '-':
            result = numberA - numberB;
            break;
        case '*':
            result = numberA * numberB;
            break;
        case '/':
            result = numberA / numberB;
            break;
        default:
            break;
    }
    return result;
}
程式碼功能都實現了,我將業務邏輯封裝到了一個方法裡,使用時直接呼叫即可,乍一看問題不大,仔細分析,發現還是有很多問題的
緊耦合vs鬆耦合
物件導向的三大特性:繼承、多型、封裝。我只用到了一個,倘若我現在要新增取餘運算,怎麼做?直接修改方法嗎?如果一不小心把加號改成減號,那就慘了,這樣的危險我們應該避免,所以最好的辦法是把所有運算都分離出去,讓他們之間相互不受影響,分析一下我們的程式碼,其實每種運算都涉及要運算的數和運算子,我們把他抽象出來,將共有特性進行抽象,這其實是為了更好的封裝。
Operation運算類
public abstract class Operation {
    public double numberA;
    public double numberB;
    public abstract double getResult();
}

加減乘除類

public class OperationAdd extends Operation {
    public double getResult() {
        double result = 0d;
        result = numberA + numberB;
        return result;
    }
}
public class OperationSub extends Operation {
    public double getResult() {
        double result = 0d;
        result = numberA - numberB;
        return result;
    }
}
剩下的幾個運算類程式碼類似,就不寫了
簡單工廠類
public class OperationFactory {

    public static Operation createOperate(char operate) {
        Operation oper = null;
        switch (operate) {
            case '+':
                oper = new OperationAdd();
                break;
            case '-':
                oper = new OperationSub();
                break;
            case '*':
                oper = new OperationMul();
                break;
            case '/':
                oper = new OperationDiv();
                break;

            default:
                break;
        }
        return oper;
    }
}
使用的時候,我們就可以這樣使用
public static void main(String[] args) {
    // TODO Auto-generated method stub
    Operation oper;
    oper= OperationFactory.createOperate('+');
    oper.numberA=5;
    oper.numberA=6;
    double result=oper.getResult();
}

看下程式的UML類圖:


這樣以來,各個運算類直接就沒有關係了,我們修改某個類也不影響其他類執行,想要新增新的運算也只是新增運運算元類和修改簡單工廠類而已。
總結
簡單工廠模式的主要優點如下:
  • 客戶端可以免除直接建立物件的職責,只關心使用物件,簡單工廠模式實現了物件建立和使用的分離。
  • 客戶端不用知道建立產品類具體類名,只要知道具體產品類所對應的引數即可。
簡單工廠模式的主要缺點如下:
  • 工廠類負責所有物件的建立邏輯,該類出問題整個系統掛掉。
  • 系統擴充套件困難,一旦新增新產品就不得不修改工廠邏輯。
  • 簡單工廠模式由於使用了靜態工廠方法,所以工廠角色無法形成基於繼承的等級結構。
參考:

相關文章