設計模式學習筆記(五):工廠方法模式

1 前言

儘管簡單工廠模式實現了對象的建立和使用分離,可是仍然存在如下兩個問題:java

  • 工廠類過於龐大,包含了大量的判斷代碼,致使維護和測試難度增大
  • 系統擴展不靈活,若是增長了新的產品類型,必須修改靜態工廠方法的業務邏輯,違反了開閉原則
  • 具體產品與工廠類之間的耦合度高,嚴重影響了系統的靈活性和擴展性

一個更好的辦法是使用工廠方法模式。數據庫

2 工廠方法模式

工廠方法模式:定義一個用於建立對象的接口,讓子類決定將哪個類實例化。
工廠方法又簡稱工廠模式或虛擬構造器模式或多態工廠模式,讓一個類的實例化延遲到其子類,是一種類建立型模式。
結構圖以下:ide

在這裏插入圖片描述

工廠方法模式包含如下四個角色:性能

  • Product(抽象產品):定義產品的接口,是工廠方法模式所建立的超類型,也就是產品對象的公共父類
  • ConcreteProduct(具體產品):實現了抽象產品接口,某種類型的具體產品由專門的具體工廠建立,具體工廠與具體產品一一對應
  • Factory(抽象工廠):在抽象工廠類中,聲明瞭工廠方法,用於返回一個產品。抽象工廠是工廠方法模式的核心,全部建立對象的工廠類都必須實現該接口
  • ConcreteFactory(具體工廠):它是抽象工廠類的子類,實現了抽象工廠中定義的工廠方法,並可由客戶端調用,返回一個具體產品類的實例

3 實例

日誌記錄器的設計:該記錄器能夠經過多種途徑保存系統的運行日誌,例如文件記錄或者數據庫記錄。測試

代碼以下:this

public class Test
{
    public static void main(String[] args) {
        LoggerFactory factory = new FileLoggerFactory();        
        Logger logger = factory.createLogger();
        logger.log();
    }
}

//抽象產品
interface Logger
{
    void log();
}

//具體產品:DatabaseLogger
class DatabaseLogger implements Logger
{
    public void log()
    {
        System.out.println("數據庫日誌記錄");
    }
}

//具體產品:FileLogger
class FileLogger implements Logger
{
    public void log()
    {
        System.out.println("文件日誌記錄");
    }
}

//抽象工廠
interface LoggerFactory
{
    Logger createLogger();
}

//具體工廠:DatabaseLoggerFactory
class DatabaseLoggerFactory implements LoggerFactory
{
    public Logger createLogger()
    {
        return new DatabaseLogger();
    }
}

//具體工廠:FileLoggerFactory
class FileLoggerFactory implements LoggerFactory
{
    public Logger createLogger()
    {
        return new FileLogger();
    }
}

4 隱藏

能夠把抽象工廠設置爲抽象類,工廠方法直接能夠對客戶端隱藏,也就是說能夠直接經過抽象工廠調用具體產品類的業務方法,客戶端無需建立具體產品,直接經過工廠類調用便可,代碼修改以下(抽象產品以及具體產品類不用修改):設計

//抽象工廠
abstract class LoggerFactory
{
    public void log()
    {
        this.createLogger().log();
    }
    public abstract Logger createLogger();
}

//具體工廠:DatabaseLoggerFactory
class DatabaseLoggerFactory extends LoggerFactory
{
    public Logger createLogger()
    {
        return new DatabaseLogger();
    }
}

//具體工廠:FileLoggerFactory
class FileLoggerFactory extends LoggerFactory
{
    public Logger createLogger()
    {
        return new FileLogger();
    }
}

public class Test
{
    public static void main(String[] args) {
        LoggerFactory factory = new FileLoggerFactory();
        factory.log();
    }
}

5 主要優勢

  • 封裝細節:工廠方法用來建立客戶所須要的產品,同時還向客戶隱藏了哪一種具體產品類將被實例化這一細節,用戶只需關心所需產品對應的工廠,無需關心建立細節,甚至無須知道具體產品類的類名
  • 多態:工廠方法的多態性可以讓工廠能夠自主肯定建立何種產品對象,而如何建立對象的細節則徹底封裝在具體工廠內部
  • 擴展性好:加入新產品時無須修改抽象工廠,抽象產品的接口,也無須修改客戶端與其餘的具體產品和具體工廠,只須要增長一個具體工廠以及具體產品,系統擴展性很好,徹底符合開閉原則

6 主要缺點

  • 類數量多:在添加新產品時,須要編寫新的具體產品類,並且還要提供與之對應的具體工廠類,系統中類的個數將成對增長,必定程度上增長了系統的複雜度,有更多的類須要編譯和運行,給系統帶來額外開銷
  • 增長理解難度:基於系統的擴展性須要引入抽象層,在客戶端中均使用了抽象層的定義,增長了系統的抽象性以及理解難度

7 適用場景

  • 客戶端不知道其所須要的對象的類:在工廠方法模式中,客戶端不須要知道具體的產品類名,只須要知道所對應的工廠便可
  • 抽象工廠類經過子類來指定建立哪一個對象:工廠方法模式中,抽象工廠類只須要提供一個建立產品的接口,而有其子類來肯定具體要建立的對象,利用面向對象的多態性和里氏代換原則,在程序運行時,子類對象將覆蓋父類對象,從而使得系統更加容易擴展

8 總結

在這裏插入圖片描述

相關文章
相關標籤/搜索