Java設(shè)計(jì)模式(二) 工廠(chǎng)方法模式

原創(chuàng)文章,轉(zhuǎn)載請(qǐng)務(wù)必將下面這段話(huà)置于文章開(kāi)頭處。
  本文轉(zhuǎn)發(fā)自Jason's Blog原文鏈接 
http://www.jasongj.com/design_pattern/factory_method/

工廠(chǎng)方法模式解決的問(wèn)題

上文《簡(jiǎn)單工廠(chǎng)模式不簡(jiǎn)單》中提到,簡(jiǎn)單工廠(chǎng)模式有如下缺點(diǎn),而工廠(chǎng)方法模式可以解決這些問(wèn)題

  • 由于工廠(chǎng)類(lèi)集中了所有實(shí)例的創(chuàng)建邏輯,這就直接導(dǎo)致一旦這個(gè)工廠(chǎng)出了問(wèn)題,所有的客戶(hù)端都會(huì)受到牽連。
  • 由于簡(jiǎn)單工廠(chǎng)模式的產(chǎn)品是基于一個(gè)共同的抽象類(lèi)或者接口,這樣一來(lái),產(chǎn)品的種類(lèi)增加的時(shí)候,即有不同的產(chǎn)品接口或者抽象類(lèi)的時(shí)候,工廠(chǎng)類(lèi)就需要判斷何時(shí)創(chuàng)建何種接口的產(chǎn)品,這就和創(chuàng)建何種種類(lèi)的產(chǎn)品相互混淆在了一起,違背了單一職責(zé)原則,導(dǎo)致系統(tǒng)喪失靈活性和可維護(hù)性。
  • 簡(jiǎn)單工廠(chǎng)模式違背了“開(kāi)放-關(guān)閉原則”,因?yàn)楫?dāng)我們新增加一個(gè)產(chǎn)品的時(shí)候必須修改工廠(chǎng)類(lèi),相應(yīng)的工廠(chǎng)類(lèi)就需要重新編譯一遍。
  • 簡(jiǎn)單工廠(chǎng)模式由于使用了靜態(tài)工廠(chǎng)方法,造成工廠(chǎng)角色無(wú)法形成基于繼承的等級(jí)結(jié)構(gòu)。

工廠(chǎng)方法模式

工廠(chǎng)方法模式介紹

工廠(chǎng)方法模式(Factory Method Pattern)又稱(chēng)為工廠(chǎng)模式,也叫多態(tài)工廠(chǎng)模式或者虛擬構(gòu)造器模式。在工廠(chǎng)方法模式中,工廠(chǎng)父類(lèi)定義創(chuàng)建產(chǎn)品對(duì)象的公共接口,具體的工廠(chǎng)子類(lèi)負(fù)責(zé)創(chuàng)建具體的產(chǎn)品對(duì)象。每一個(gè)工廠(chǎng)子類(lèi)負(fù)責(zé)創(chuàng)建一種具體產(chǎn)品。

工廠(chǎng)方法模式類(lèi)圖

工廠(chǎng)模式類(lèi)圖如下 (點(diǎn)擊可查看大圖)


Factory Method Pattern Class Diagram
Factory Method Pattern Class Diagram

工廠(chǎng)方法模式角色劃分

  • 抽象產(chǎn)品(或者產(chǎn)品接口),如上圖中IUserDao
  • 具體產(chǎn)品,如上圖中的MySQLUserDao,PostgreSQLUserDao和OracleUserDao
  • 抽象工廠(chǎng)(或者工廠(chǎng)接口),如IFactory
  • 具體工廠(chǎng),如MySQLFactory,PostgreSQLFactory和OracleFactory

工廠(chǎng)方法模式使用方式

如簡(jiǎn)單工廠(chǎng)模式直接使用靜態(tài)工廠(chǎng)方法創(chuàng)建產(chǎn)品對(duì)象不同,在工廠(chǎng)方法,客戶(hù)端通過(guò)實(shí)例化具體的工廠(chǎng)類(lèi),并調(diào)用其創(chuàng)建實(shí)例接口創(chuàng)建具體產(chǎn)品類(lèi)的實(shí)例。根據(jù)依賴(lài)倒置原則,具體工廠(chǎng)類(lèi)的實(shí)例由工廠(chǎng)接口引用(客戶(hù)端依賴(lài)于抽象工廠(chǎng)而非具體工廠(chǎng)),具體產(chǎn)品的實(shí)例由產(chǎn)品接口引用(客戶(hù)端和工廠(chǎng)依賴(lài)于抽象產(chǎn)品而非具體產(chǎn)品)。具體調(diào)用代碼如下

package com.jasongj.client;

import com.jasongj.dao.IUserDao;
import com.jasongj.factory.IDaoFactory;
import com.jasongj.factory.MySQLDaoFactory;

public class Client {

  public static void main(String[] args) {
    IDaoFactory factory = new MySQLDaoFactory();
    IUserDao userDao = factory.createUserDao();
    userDao.getUser("admin");

  }

}

工廠(chǎng)方法模式示例代碼

本文所述工廠(chǎng)方法模式示例代碼可從作者Github下載

工廠(chǎng)方法模式優(yōu)點(diǎn)

  • 因?yàn)槊總€(gè)具體工廠(chǎng)類(lèi)只負(fù)責(zé)創(chuàng)建產(chǎn)品,沒(méi)有簡(jiǎn)單工廠(chǎng)中的邏輯判斷,因此符合單一職責(zé)原則。
  • 與簡(jiǎn)單工廠(chǎng)模式不同,工廠(chǎng)方法并不使用靜態(tài)工廠(chǎng)方法,可以形成基于繼承的等級(jí)結(jié)構(gòu)。
  • 新增一種產(chǎn)品時(shí),只需要增加相應(yīng)的具體產(chǎn)品類(lèi)和相應(yīng)的工廠(chǎng)子類(lèi)即可,相比于簡(jiǎn)單工廠(chǎng)模式需要修改判斷邏輯而言,工廠(chǎng)方法模式更符合開(kāi)-閉原則。

工廠(chǎng)方法模式缺點(diǎn)

  • 添加新產(chǎn)品時(shí),除了增加新產(chǎn)品類(lèi)外,還要提供與之對(duì)應(yīng)的具體工廠(chǎng)類(lèi),系統(tǒng)類(lèi)的個(gè)數(shù)將成對(duì)增加,在一定程度上增加了系統(tǒng)的復(fù)雜度,有更多的類(lèi)需要編譯和運(yùn)行,會(huì)給系統(tǒng)帶來(lái)一些額外的開(kāi)銷(xiāo)。
  • 雖然保證了工廠(chǎng)方法內(nèi)的對(duì)修改關(guān)閉,但對(duì)于使用工廠(chǎng)方法的類(lèi),如果要換用另外一種產(chǎn)品,仍然需要修改實(shí)例化的具體工廠(chǎng)。
  • 一個(gè)具體工廠(chǎng)只能創(chuàng)建一種具體產(chǎn)品

簡(jiǎn)單工廠(chǎng)模式與OOP原則

已遵循的原則

  • 依賴(lài)倒置原則
  • 迪米特法則
  • 里氏替換原則
  • 接口隔離原則
  • 單一職責(zé)原則(每個(gè)工廠(chǎng)只負(fù)責(zé)創(chuàng)建自己的具體產(chǎn)品,沒(méi)有簡(jiǎn)單工廠(chǎng)中的邏輯判斷)
  • 開(kāi)閉原則(增加新的產(chǎn)品,不像簡(jiǎn)單工廠(chǎng)那樣需要修改已有的工廠(chǎng),而只需增加相應(yīng)的具體工廠(chǎng)類(lèi))

未遵循的原則

  • 開(kāi)閉原則(雖然工廠(chǎng)對(duì)修改關(guān)閉了,但更換產(chǎn)品時(shí),客戶(hù)代碼還是需要修改)

Java設(shè)計(jì)模式系列

最后編輯于
?著作權(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)容僅代表作者本人觀(guān)點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

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

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