天道不一定酬所有勤
但是,天道只酬勤

設計模式(四)——簡單工廠模式

新專題:設計模式,我會在博客(http://www.057299.live)及微信公眾號(hollischuang)同步更新,歡迎共同學習。

設計模式(一)——設計模式概述中簡單介紹了設計模式以及各種設計模式的基本概念,本文主要介紹簡單工廠模式,包括其概念、用途、實現方式及存在的問題等。

概念

簡單工廠模式是屬于創建型模式,又叫做靜態工廠方法(Static Factory Method)模式。簡單工廠模式是由一個工廠對象決定創建出哪一種產品類的實例。簡單工廠模式是工廠模式家族中最簡單實用的模式,可以理解為是不同工廠模式的一個特殊實現。

值得注意的是,簡單工廠模式并不屬于23種GOF設計模式之一。但是他是抽象工廠模式,工廠方法模式的基礎,并且也有廣泛的應用。

用途

在介紹簡單工廠模式之前,我們嘗試解決以下問題:

現在我們要使用面向對象的形式定義計算器,為了實現各算法之間的解耦。主要的用到的類如下:

// 計算類的基類
public abstract class Operation {

    private double value1 = 0;
    private double value2 = 0;

    public double getValue1() {
        return value1;
    }

    public void setValue1(double value1) {
        this.value1 = value1;
    }

    public double getValue2() {
        return value2;
    }

    public void setValue2(double value2) {
        this.value2 = value2;
    }

    protected abstract double getResule();
}

//加法
public class OperationAdd extends Operation {

    @Override
    protected double getResule() {
        return getValue1() + getValue2();
    }
}

//減法
public class OperationSub extends Operation {

    @Override
    protected double getResule() {
        return getValue1() - getValue2();
    }
}

//乘法
public class OperationMul extends Operation {

    @Override
    protected double getResule() {
        return getValue1() * getValue2();
    }
}

//除法
public class OperationDiv extends Operation {

    @Override
    protected double getResule() {
        if (getValue2() != 0) {
            return getValue1() / getValue2();
        }
        throw new IllegalArgumentException("除數不能為零");
    }
}

當我想要執行加法運算時,可以使用如下代碼:

public class Main {

    public static void main(String[] args) {
        OperationAdd operationAdd = new OperationAdd();
        operationAdd.setValue1(10);
        operationAdd.setValue2(5);
        System.out.println(operationAdd.getResule());
    }
}

當我需要執行減法運算時,我就要創建一個OperationSub類。也就是說,我想要使用不同的運算的時候就要創建不同的類,并且要明確知道該類的名字。那么這種重復的創建類的工作其實可以放到一個統一的工廠類中。

簡單工廠模式有以下優點:

1、一個調用者想創建一個對象,只要知道其名稱就可以了。

2、屏蔽產品的具體實現,調用者只關心產品的接口。

實現方式

簡單工廠模式其實和他的名字一樣,很簡單。先來看看它的組成:

1) 工廠類角色:這是本模式的核心,含有一定的商業邏輯和判斷邏輯。在java中它往往由 一個具體類實現。(OperationFactory)

2) 抽象產品角色:它一般是具體產品繼承的父類或者實現的接口。在java中由接口或者抽象類來實現。(Operation)

3) 具體產品角色:工廠類所創建的對象就是此角色的實例。在java中由一個具體類實現。 來用類圖來清晰的表示下的它們之間的關系(OperationAdd\OperationSub等)

QQ20160411-0

在原有類的基礎上,定義工廠類:

//工廠類
public class OperationFactory {

    public static Operation createOperation(String operation) {
        Operation oper = null;
        switch (operation) {

            case "+":
                oper = new OperationAdd();
                break;

            case "-":
                oper = new OperationSub();
                break;

            case "*":
                oper = new OperationMul();
                break;

            case "/":
                oper = new OperationDiv();
                break;
            default:
                throw new UnsupportedOperationException("不支持該操作");
        }
        return oper;
    }
}

有了工廠類之后,可以使用工廠創建對象:

Operation operationAdd = OperationFactory.createOperation("+");
operationAdd.setValue1(10);
operationAdd.setValue2(5);
System.out.println(operationAdd.getResule());

通過簡單工廠模式,該計算器的使用者不需要關系實現加法邏輯的那個類的具體名字,他只要知道該類對應的參數”+”就可以了。

簡單工廠模式存在的問題

在設計模式(一)——設計模式概述中介紹了設計模式一般應該遵循的幾個原則。

下面我們從開閉原則(對擴展開放;對修改封閉)上來分析下簡單工廠模式。當我們需要增加一種計算時,例如開平方。這個時候我們需要先定義一個類繼承Operation類,其中實現平方的代碼。除此之外我們還要修改OperationFactory類的代碼,增加一個case。這顯然是違背開閉原則的??上攵獙τ谛庐a品的加入,工廠類是很被動的。

我們舉的例子是最簡單的情況。而在實際應用中,很可能產品是一個多層次的樹狀結構。 簡單工廠可能就不太適用了。

總結

工廠類是整個簡單工廠模式的關鍵。包含了必要的邏輯判斷,根據外界給定的信息,決定究竟應該創建哪個具體類的對象。通過使用工廠類,外界可以從直接創建具體產品對象的尷尬局面擺脫出來,僅僅需要負責“消費”對象就可以了。而不必管這些對象究竟如何創建及如何組織的。明確了各自的職責和權利,有利于整個軟件體系結構的優化。

但是

由于工廠類集中了所有實例的創建邏輯,違反了高內聚責任分配原則,將全部創建邏輯集中到了一個工廠類中;它所能創建的類只能是事先考慮到的,如果需要添加新的類,則就需要改變工廠類了。

當系統中的具體產品類不斷增多時候,可能會出現要求工廠類根據不同條件創建不同實例的需求.這種對條件的判斷和對具體產品類型的判斷交錯在一起,很難避免模塊功能的蔓延,對系統的維護和擴展非常不利;

這些缺點在工廠方法模式中得到了一定的解決。

文中所有代碼見GitHub

參考資料

大話設計模式

(全文完) 歡迎關注『Java之道』微信公眾號
贊(0)
如未加特殊說明,此網站文章均為原創,轉載必須注明出處。HollisChuang's Blog » 設計模式(四)——簡單工廠模式
分享到: 更多 (0)

評論 7

  • 昵稱 (必填)
  • 郵箱 (必填)
  • 網址
  1. #1

    講解非常詳細。

    TGA4年前 (2016-04-30)回復
  2. #2

    switch可以使用string?

    李濤4年前 (2016-05-08)回復
    • JDK1.7以后就可以了。 可以參考這篇文章:http://www.057299.live/archives/61

      HollisChuang4年前 (2016-05-09)回復
  3. #3

    你好, 在你的博客 受益匪淺,在這篇博文里,您的uml圖好像有一個錯誤地方,
    在 簡單工廠類 到運算類 之間,應該屬于依賴關系,應該用 帶箭頭的虛線表示,
    如果有錯誤,請指出??!

    稀里糊涂4年前 (2016-07-20)回復
  4. #4

    下面那段代碼一眼看上去switch case 有點多 我之前也用過類似的方式,不過我傳的參數不是+-*/,是直接傳過去一個類名的字符串,然后用反射去實例這個類,比如:
    Operation operationAdd = OperationFactory.createOperation(OperationAdd);

    public static Operation createOperation(String operation) {
    Operation oper = 反射實例operation對象;
    return oper;
    [emoji:ff5d]

    千尋啊千尋3年前 (2017-06-15)回復
    • 感覺使用反射只是看起來不錯。因為調用層怎么知道那個類名對應那個操作呢?這個問題沒法解決。

      我阿強呢2年前 (2017-10-20)回復
      • 這個就要做入參的接口文檔說明了 我們之前做的是第三方登錄的,入參就是Qq、Weibo。。。。然后加上QqService做的實例

        千尋啊千尋2年前 (2017-11-02)回復

HollisChuang's Blog

聯系我關于我
大乐透复式返奖 北京11选五的走势图 白小姐四肖必选一肖930 山西11选五开奖结果 11选5一定牛走势图 吉林11选5任选5 11选五5一定牛北京 不怕连挂的倍投 山东11选五直选遗漏 黑龙江快乐十分走势图 13835平特一肖