天天看點

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

概述

簡單工廠模式(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類圖:

這樣以來,各個運算類直接就沒有關系了,我們修改某個類也不影響其他類運作,想要添加新的運算也隻是添加運算子類和修改簡單工廠類而已。

總結

簡單工廠模式的主要優點如下:

  • 用戶端可以免除直接建立對象的職責,隻關心使用對象,簡單工廠模式實作了對象建立和使用的分離。
  • 用戶端不用知道建立産品類具體類名,隻要知道具體産品類所對應的參數即可。

簡單工廠模式的主要缺點如下:

  • 工廠類負責所有對象的建立邏輯,該類出問題整個系統挂掉。
  • 系統擴充困難,一旦添加新産品就不得不修改工廠邏輯。
  • 簡單工廠模式由于使用了靜态工廠方法,是以工廠角色無法形成基于繼承的等級結構。

參考:

http://blog.csdn.net/yanbober/article/details/45312395 http://blog.csdn.net/lmj623565791/article/details/24460585

繼續閱讀