欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Java設(shè)計(jì)模式中的工廠及抽象工廠模式解析

 更新時間:2023年12月05日 09:02:45   作者:遇見更好的自己、  
這篇文章主要介紹了Java設(shè)計(jì)模式中的工廠及抽象工廠模式解析,工廠模式作為創(chuàng)建型設(shè)計(jì)模式中常見的設(shè)計(jì)方法,一般情況下,工廠模式分為3種,簡單工作、工廠方法、抽象工作,其實(shí)簡單工廠只是工廠方法的一種特例,需要的朋友可以參考下

前言

工廠模式作為創(chuàng)建型設(shè)計(jì)模式中常見的設(shè)計(jì)方法,一般情況下,工廠模式分為3種,簡單工作、工廠方法、抽象工作。

其實(shí)簡單工廠只是工廠方法的一種特例。

接下來,我們就來學(xué)習(xí)下如何實(shí)現(xiàn)工廠模式及幾種工廠模式之間的區(qū)分。

一、簡單工廠

我們在日常開發(fā)的過程中,一定遇到過,根據(jù)不同的類型去創(chuàng)建不同的類的業(yè)務(wù)場景

從而代碼中就會充斥著一段if,else的邏輯,對于有代碼潔癖的同事來說,可能看見過多的if,else就會比較煩,想著方法去去除掉。

這時,簡單工廠的設(shè)計(jì)模式就派上用場了。

假設(shè)我們有如下場景,我們需要根據(jù)配置文件的后綴(json、xml、yaml、properties)選擇不同的解析器,將存儲在文件中的配置解析成內(nèi)存對象RuleConfig。

代碼如下:

 
public class RuleConfigSource {
  public RuleConfig load(String ruleConfigFilePath) {
    String ruleConfigFileExtension = getFileExtension(ruleConfigFilePath);
    IRuleConfigParser parser = RuleConfigParserFactory.createParser(ruleConfigFileExtension);
    if (parser == null) {
      throw new InvalidRuleConfigException(
              "Rule config file format is not supported: " + ruleConfigFilePath);
    }
    String configText = "";
    //從ruleConfigFilePath文件中讀取配置文本到configText中
    RuleConfig ruleConfig = parser.parse(configText);
    return ruleConfig;
  }
  private String getFileExtension(String filePath) {
    //...解析文件名獲取擴(kuò)展名,比如rule.json,返回json
    return "json";
  }
}
public class RuleConfigParserFactory {
  public static IRuleConfigParser createParser(String configFormat) {
    IRuleConfigParser parser = null;
    if ("json".equalsIgnoreCase(configFormat)) {
      parser = new JsonRuleConfigParser();
    } else if ("xml".equalsIgnoreCase(configFormat)) {
      parser = new XmlRuleConfigParser();
    } else if ("yaml".equalsIgnoreCase(configFormat)) {
      parser = new YamlRuleConfigParser();
    } else if ("properties".equalsIgnoreCase(configFormat)) {
      parser = new PropertiesRuleConfigParser();
    }
    return parser;
  }
}

另外一種簡單工廠的實(shí)現(xiàn)方式如下:

 
public class RuleConfigParserFactory {
  private static final Map<String, RuleConfigParser> cachedParsers = new HashMap<>();
  static {
    cachedParsers.put("json", new JsonRuleConfigParser());
    cachedParsers.put("xml", new XmlRuleConfigParser());
    cachedParsers.put("yaml", new YamlRuleConfigParser());
    cachedParsers.put("properties", new PropertiesRuleConfigParser());
  }
  public static IRuleConfigParser createParser(String configFormat) {
    if (configFormat == null || configFormat.isEmpty()) {
      return null;//返回null還是IllegalArgumentException全憑你自己說了算
    }
    IRuleConfigParser parser = cachedParsers.get(configFormat.toLowerCase());
    return parser;
  }
}

對于上面兩種簡單工廠模式的實(shí)現(xiàn)方法,如果我們要添加新的 parser,那勢必要改動到 RuleConfigParserFactory 的代碼,那這是不是違反開閉原則呢?

實(shí)際上,如果不是需要頻繁地添加新的 parser,只是偶爾修改一下 RuleConfigParserFactory 代碼,稍微不符合開閉原則,也是完全可以接受的。

總結(jié):盡管簡單工廠模式的代碼實(shí)現(xiàn)中,有多處 if 分支判斷邏輯,違背開閉原則,但權(quán)衡擴(kuò)展性和可讀性,這樣的代碼實(shí)現(xiàn)在大多數(shù)情況下(比如,不需要頻繁地添加 parser,也沒有太多的 parser)是沒有問題的。

二、工廠方法(Factory Method)

上面的提到的簡單工廠方法有一個比較大缺點(diǎn),那就是不符合開閉原則,當(dāng)新增一個parser的時候,我們需要更改Factory的代碼。

那我們有么有辦法可以解決這個問題勒。

那就是工廠方法的設(shè)計(jì)模式,他能利用多態(tài)的能力,對簡單工廠進(jìn)行改造。

代碼如下:

 
public interface IRuleConfigParserFactory {
  IRuleConfigParser createParser();
}
public class JsonRuleConfigParserFactory implements IRuleConfigParserFactory {
  @Override
  public IRuleConfigParser createParser() {
    return new JsonRuleConfigParser();
  }
}
public class XmlRuleConfigParserFactory implements IRuleConfigParserFactory {
  @Override
  public IRuleConfigParser createParser() {
    return new XmlRuleConfigParser();
  }
}
public class YamlRuleConfigParserFactory implements IRuleConfigParserFactory {
  @Override
  public IRuleConfigParser createParser() {
    return new YamlRuleConfigParser();
  }
}
public class PropertiesRuleConfigParserFactory implements IRuleConfigParserFactory {
  @Override
  public IRuleConfigParser createParser() {
    return new PropertiesRuleConfigParser();
  }
}

用工廠方法的方式實(shí)現(xiàn)上述代碼:

 
public class RuleConfigSource {
  public RuleConfig load(String ruleConfigFilePath) {
    String ruleConfigFileExtension = getFileExtension(ruleConfigFilePath);
    IRuleConfigParserFactory parserFactory = null;
    if ("json".equalsIgnoreCase(ruleConfigFileExtension)) {
      parserFactory = new JsonRuleConfigParserFactory();
    } else if ("xml".equalsIgnoreCase(ruleConfigFileExtension)) {
      parserFactory = new XmlRuleConfigParserFactory();
    } else if ("yaml".equalsIgnoreCase(ruleConfigFileExtension)) {
      parserFactory = new YamlRuleConfigParserFactory();
    } else if ("properties".equalsIgnoreCase(ruleConfigFileExtension)) {
      parserFactory = new PropertiesRuleConfigParserFactory();
    } else {
      throw new InvalidRuleConfigException("Rule config file format is not supported: " + ruleConfigFilePath);
    }
    IRuleConfigParser parser = parserFactory.createParser();
    String configText = "";
    //從ruleConfigFilePath文件中讀取配置文本到configText中
    RuleConfig ruleConfig = parser.parse(configText);
    return ruleConfig;
  }
  private String getFileExtension(String filePath) {
    //...解析文件名獲取擴(kuò)展名,比如rule.json,返回json
    return "json";
  }
}

從上面的代碼實(shí)現(xiàn)來看,工廠類對象的創(chuàng)建邏輯又耦合進(jìn)了 load() 函數(shù)中,跟我們最初的代碼版本非常相似,引入工廠方法非但沒有解決問題,反倒讓設(shè)計(jì)變得更加復(fù)雜了。那怎么來解決這個問題呢?

我們可以為工廠類再創(chuàng)建一個簡單工廠,也就是工廠的工廠,用來創(chuàng)建工廠類對象。這段話聽起來有點(diǎn)繞,我把代碼實(shí)現(xiàn)出來了,你一看就能明白了。其中,RuleConfigParserFactoryMap 類是創(chuàng)建工廠對象的工廠類,getParserFactory() 返回的是緩存好的單例工廠對象。

 
public class RuleConfigSource {
  public RuleConfig load(String ruleConfigFilePath) {
    String ruleConfigFileExtension = getFileExtension(ruleConfigFilePath);
    IRuleConfigParserFactory parserFactory = RuleConfigParserFactoryMap.getParserFactory(ruleConfigFileExtension);
    if (parserFactory == null) {
      throw new InvalidRuleConfigException("Rule config file format is not supported: " + ruleConfigFilePath);
    }
    IRuleConfigParser parser = parserFactory.createParser();
    String configText = "";
    //從ruleConfigFilePath文件中讀取配置文本到configText中
    RuleConfig ruleConfig = parser.parse(configText);
    return ruleConfig;
  }
  private String getFileExtension(String filePath) {
    //...解析文件名獲取擴(kuò)展名,比如rule.json,返回json
    return "json";
  }
}
//因?yàn)楣S類只包含方法,不包含成員變量,完全可以復(fù)用,
//不需要每次都創(chuàng)建新的工廠類對象,所以,簡單工廠模式的第二種實(shí)現(xiàn)思路更加合適。
public class RuleConfigParserFactoryMap { //工廠的工廠
  private static final Map<String, IRuleConfigParserFactory> cachedFactories = new HashMap<>();
  static {
    cachedFactories.put("json", new JsonRuleConfigParserFactory());
    cachedFactories.put("xml", new XmlRuleConfigParserFactory());
    cachedFactories.put("yaml", new YamlRuleConfigParserFactory());
    cachedFactories.put("properties", new PropertiesRuleConfigParserFactory());
  }
  public static IRuleConfigParserFactory getParserFactory(String type) {
    if (type == null || type.isEmpty()) {
      return null;
    }
    IRuleConfigParserFactory parserFactory = cachedFactories.get(type.toLowerCase());
    return parserFactory;
  }
}

總結(jié):對于規(guī)則配置文件解析這個應(yīng)用場景來說,工廠模式需要額外創(chuàng)建諸多 Factory 類,也會增加代碼的復(fù)雜性,而且,每個 Factory 類只是做簡單的 new 操作,功能非常單?。ㄖ挥幸恍写a),也沒必要設(shè)計(jì)成獨(dú)立的類,所以,在這個應(yīng)用場景下,簡單工廠模式簡單好用,比工廠方法模式更加合適。

三、如何選擇使用簡單工廠和工廠方式

當(dāng)對象的創(chuàng)建邏輯比較復(fù)雜,不只是簡單的 new 一下就可以,而是要組合其他類對象,做各種初始化操作的時候,我們推薦使用工廠方法模式,將復(fù)雜的創(chuàng)建邏輯拆分到多個工廠類中,讓每個工廠類都不至于過于復(fù)雜。而使用簡單工廠模式,將所有的創(chuàng)建邏輯都放到一個工廠類中,會導(dǎo)致這個工廠類變得很復(fù)雜。

除此之外,在某些場景下,如果對象不可復(fù)用,那工廠類每次都要返回不同的對象。如果我們使用簡單工廠模式來實(shí)現(xiàn),就只能選擇第一種包含 if 分支邏輯的實(shí)現(xiàn)方式。如果我們還想避免煩人的 if-else 分支邏輯,這個時候,我們就推薦使用工廠方法模式。

四、抽象工廠

在簡單工廠和工廠方法中,類只有一種分類方式。比如,在規(guī)則配置解析那個例子中,解析器類只會根據(jù)配置文件格式(Json、Xml、Yaml……)來分類。但是,如果類有兩種分類方式,比如,我們既可以按照配置文件格式來分類,也可以按照解析的對象(Rule 規(guī)則配置還是 System 系統(tǒng)配置)來分類,那就會對應(yīng)下面這 8 個 parser 類。

針對規(guī)則配置的解析器:基于接口IRuleConfigParser

  • JsonRuleConfigParser
  • XmlRuleConfigParser
  • YamlRuleConfigParser
  • PropertiesRuleConfigParser

針對系統(tǒng)配置的解析器:基于接口ISystemConfigParser

  • JsonSystemConfigParser
  • XmlSystemConfigParser
  • YamlSystemConfigParser
  • PropertiesSystemConfigParser

針對這種特殊的場景,如果還是繼續(xù)用工廠方法來實(shí)現(xiàn)的話,我們要針對每個 parser 都編寫一個工廠類,也就是要編寫 8 個工廠類。

如果我們未來還需要增加針對業(yè)務(wù)配置的解析器(比如 IBizConfigParser),那就要再對應(yīng)地增加 4 個工廠類。而我們知道,過多的類也會讓系統(tǒng)難維護(hù)。

這個問題該怎么解決呢?

抽象工廠就是針對這種非常特殊的場景而誕生的。

我們可以讓一個工廠負(fù)責(zé)創(chuàng)建多個不同類型的對象(IRuleConfigParser、ISystemConfigParser 等),而不是只創(chuàng)建一種 parser 對象。

這樣就可以有效地減少工廠類的個數(shù)。

具體的代碼實(shí)現(xiàn)如下所示:

 
public interface IConfigParserFactory {
  IRuleConfigParser createRuleParser();
  ISystemConfigParser createSystemParser();
  //此處可以擴(kuò)展新的parser類型,比如IBizConfigParser
}
public class JsonConfigParserFactory implements IConfigParserFactory {
  @Override
  public IRuleConfigParser createRuleParser() {
    return new JsonRuleConfigParser();
  }
  @Override
  public ISystemConfigParser createSystemParser() {
    return new JsonSystemConfigParser();
  }
}
public class XmlConfigParserFactory implements IConfigParserFactory {
  @Override
  public IRuleConfigParser createRuleParser() {
    return new XmlRuleConfigParser();
  }
  @Override
  public ISystemConfigParser createSystemParser() {
    return new XmlSystemConfigParser();
  }
}
// 省略YamlConfigParserFactory和PropertiesConfigParserFactory代碼

總結(jié)

當(dāng)創(chuàng)建邏輯比較復(fù)雜,是一個“大工程”的時候,我們就考慮使用工廠模式,封裝對象的創(chuàng)建過程,將對象的創(chuàng)建和使用相分離。

何為創(chuàng)建邏輯比較復(fù)雜呢?

  • 第一種情況:類似規(guī)則配置解析的例子,代碼中存在 if-else 分支判斷,動態(tài)地根據(jù)不同的類型創(chuàng)建不同的對象。針對這種情況,我們就考慮使用工廠模式,將這一大坨 if-else 創(chuàng)建對象的代碼抽離出來,放到工廠類中。
  • 還有一種情況,盡管我們不需要根據(jù)不同的類型創(chuàng)建不同的對象,但是,單個對象本身的創(chuàng)建過程比較復(fù)雜,比如前面提到的要組合其他類對象,做各種初始化操作。在這種情況下,我們也可以考慮使用工廠模式,將對象的創(chuàng)建過程封裝到工廠類中。

現(xiàn)在,我們上升一個思維層面來看工廠模式,它的作用無外乎下面這四個。這也是判斷要不要使用工廠模式的最本質(zhì)的參考標(biāo)準(zhǔn)。

  • 封裝變化:創(chuàng)建邏輯有可能變化,封裝成工廠類之后,創(chuàng)建邏輯的變更對調(diào)用者透明。
  • 代碼復(fù)用:創(chuàng)建代碼抽離到獨(dú)立的工廠類之后可以復(fù)用。
  • 隔離復(fù)雜性:封裝復(fù)雜的創(chuàng)建邏輯,調(diào)用者無需了解如何創(chuàng)建對象。
  • 控制復(fù)雜度:將創(chuàng)建代碼抽離出來,讓原本的函數(shù)或類職責(zé)更單一,代碼更簡潔

到此這篇關(guān)于Java設(shè)計(jì)模式中的工廠及抽象工廠模式解析的文章就介紹到這了,更多相關(guān)Java工廠及抽象工廠模式內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Springboot2.6.x的啟動流程與自動配置詳解

    Springboot2.6.x的啟動流程與自動配置詳解

    這篇文章主要給大家介紹了關(guān)于Springboot2.6.x的啟動流程與自動配置的相關(guān)資料,文中通過實(shí)例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2022-01-01
  • Java中Controller、Service、Dao/Mapper層的區(qū)別與用法

    Java中Controller、Service、Dao/Mapper層的區(qū)別與用法

    在Java開發(fā)中,通常會采用三層架構(gòu)(或稱MVC架構(gòu))來劃分程序的職責(zé)和功能,分別是Controller層、Service層、Dao/Mapper層,本文將詳細(xì)給大家介紹了三層的區(qū)別和用法,需要的朋友可以參考下
    2023-05-05
  • JAVA內(nèi)存模型(JMM)詳解

    JAVA內(nèi)存模型(JMM)詳解

    這篇文章主要介紹了JAVA內(nèi)存模型(JMM)詳解的相關(guān)資料,需要的朋友可以參考下
    2022-12-12
  • 基于Java SSM框架開發(fā)圖書借閱系統(tǒng)源代碼

    基于Java SSM框架開發(fā)圖書借閱系統(tǒng)源代碼

    本文給大家介紹了基于Java SSM框架開發(fā)圖書借閱系統(tǒng),開發(fā)環(huán)境基于idea2020+mysql數(shù)據(jù)庫,前端框架使用bootstrap4框架,完美了實(shí)現(xiàn)圖書借閱系統(tǒng),喜歡的朋友快來體驗(yàn)吧
    2021-05-05
  • Spring Cloud Feign的使用案例詳解

    Spring Cloud Feign的使用案例詳解

    Feign是Netflix開發(fā)的?個輕量級RESTful的HTTP服務(wù)客戶端(?它來發(fā)起請求,遠(yuǎn)程調(diào)?的),是以Java接?注解的?式調(diào)?Http請求,F(xiàn)eign被?泛應(yīng)?在Spring Cloud 的解決?案中,本文給大家介紹Spring Cloud Feign的使用,感興趣的朋友一起看看吧
    2023-02-02
  • 關(guān)于Spring中@Lazy注解的使用

    關(guān)于Spring中@Lazy注解的使用

    這篇文章主要介紹了關(guān)于Spring中@Lazy注解的使用,@Lazy注解用于標(biāo)識bean是否需要延遲加載,沒加注解之前主要容器啟動就會實(shí)例化bean,本文提供了部分實(shí)現(xiàn)代碼,需要的朋友可以參考下
    2023-08-08
  • IDEA配置Gradle及Gradle安裝的實(shí)現(xiàn)步驟

    IDEA配置Gradle及Gradle安裝的實(shí)現(xiàn)步驟

    本文主要介紹了IDEA配置Gradle及Gradle安裝的實(shí)現(xiàn)步驟,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-08-08
  • SpringBoot操作spark處理hdfs文件的操作方法

    SpringBoot操作spark處理hdfs文件的操作方法

    本文介紹了如何使用Spring Boot操作Spark處理HDFS文件,包括導(dǎo)入依賴、配置Spark信息、編寫Controller和Service處理地鐵數(shù)據(jù)、運(yùn)行項(xiàng)目以及觀察Spark和HDFS的狀態(tài),感興趣的朋友跟隨小編一起看看吧
    2025-01-01
  • SSH 框架簡介

    SSH 框架簡介

    SSH是 struts+spring+hibernate的一個集成框架,是目前較流行的一種web應(yīng)用程序開源框架。本文給大家詳細(xì)看一下組成SSH的這三個框架
    2017-09-09
  • Java日常練習(xí)題,每天進(jìn)步一點(diǎn)點(diǎn)(21)

    Java日常練習(xí)題,每天進(jìn)步一點(diǎn)點(diǎn)(21)

    下面小編就為大家?guī)硪黄狫ava基礎(chǔ)的幾道練習(xí)題(分享)。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧,希望可以幫到你
    2021-07-07

最新評論