最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

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

 更新時(shí)間: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ù)場景

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

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

假設(shè)我們有如下場景,我們需要根據(jù)配置文件的后綴(json、xml、yaml、properties)選擇不同的解析器,將存儲(chǔ)在文件中的配置解析成內(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,那勢必要改動(dòng)到 RuleConfigParserFactory 的代碼,那這是不是違反開閉原則呢?

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

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

二、工廠方法(Factory Method)

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

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

那就是工廠方法的設(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ù)雜了。那怎么來解決這個(gè)問題呢?

我們可以為工廠類再創(chuàng)建一個(gè)簡單工廠,也就是工廠的工廠,用來創(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ī)則配置文件解析這個(gè)應(yīng)用場景來說,工廠模式需要額外創(chuàng)建諸多 Factory 類,也會(huì)增加代碼的復(fù)雜性,而且,每個(gè) Factory 類只是做簡單的 new 操作,功能非常單?。ㄖ挥幸恍写a),也沒必要設(shè)計(jì)成獨(dú)立的類,所以,在這個(gè)應(yīng)用場景下,簡單工廠模式簡單好用,比工廠方法模式更加合適。

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

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

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

四、抽象工廠

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

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

  • JsonRuleConfigParser
  • XmlRuleConfigParser
  • YamlRuleConfigParser
  • PropertiesRuleConfigParser

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

  • JsonSystemConfigParser
  • XmlSystemConfigParser
  • YamlSystemConfigParser
  • PropertiesSystemConfigParser

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

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

這個(gè)問題該怎么解決呢?

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

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

這樣就可以有效地減少工廠類的個(gè)數(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ù)雜,是一個(gè)“大工程”的時(shí)候,我們就考慮使用工廠模式,封裝對象的創(chuàng)建過程,將對象的創(chuàng)建和使用相分離。

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

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

現(xiàn)在,我們上升一個(gè)思維層面來看工廠模式,它的作用無外乎下面這四個(gè)。這也是判斷要不要使用工廠模式的最本質(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)文章

  • Spring Boot集成ShedLock分布式定時(shí)任務(wù)的實(shí)現(xiàn)示例

    Spring Boot集成ShedLock分布式定時(shí)任務(wù)的實(shí)現(xiàn)示例

    ShedLock確保您計(jì)劃的任務(wù)最多同時(shí)執(zhí)行一次。如果一個(gè)任務(wù)正在一個(gè)節(jié)點(diǎn)上執(zhí)行,則它會(huì)獲得一個(gè)鎖,該鎖將阻止從另一個(gè)節(jié)點(diǎn)(或線程)執(zhí)行同一任務(wù)。
    2021-05-05
  • SpringBoot實(shí)現(xiàn)接口校驗(yàn)簽名調(diào)用的項(xiàng)目實(shí)踐

    SpringBoot實(shí)現(xiàn)接口校驗(yàn)簽名調(diào)用的項(xiàng)目實(shí)踐

    在以SpringBoot開發(fā)后臺API接口時(shí),會(huì)存在哪些接口不安全的因素呢?通常如何去解決的呢?本文主要介紹了SpringBoot實(shí)現(xiàn)接口校驗(yàn)簽名調(diào)用的項(xiàng)目實(shí)踐,感興趣的可以了解一下
    2023-09-09
  • druid以及監(jiān)控臺使用及配置過程

    druid以及監(jiān)控臺使用及配置過程

    這篇文章主要介紹了如何在Spring?Boot項(xiàng)目中集成和配置Druid數(shù)據(jù)源,包括添加依賴、配置數(shù)據(jù)源、監(jiān)控臺配置以及Druid常用啟動(dòng)器的使用
    2025-11-11
  • Java 8中Stream API的這些奇技淫巧!你Get了嗎?

    Java 8中Stream API的這些奇技淫巧!你Get了嗎?

    這篇文章主要介紹了Java 8中Stream API的這些奇技淫巧!你Get了嗎?文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-08-08
  • feign 如何獲取請求真實(shí)目的ip地址

    feign 如何獲取請求真實(shí)目的ip地址

    這篇文章主要介紹了feign 獲取請求真實(shí)目的ip地址操作,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-06-06
  • springboot集成測試?yán)锏膔edis

    springboot集成測試?yán)锏膔edis

    這篇文章主要介紹了springboot集成測試?yán)锏膔edis,本文給大家分享了源碼,添加依賴添加mock的方法,需要的朋友可以參考下
    2018-11-11
  • @Scheduled 如何讀取動(dòng)態(tài)配置文件

    @Scheduled 如何讀取動(dòng)態(tài)配置文件

    這篇文章主要介紹了@Scheduled 如何讀取動(dòng)態(tài)配置文件的操作,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-06-06
  • 超詳細(xì)講解SpringBoot參數(shù)校驗(yàn)實(shí)例

    超詳細(xì)講解SpringBoot參數(shù)校驗(yàn)實(shí)例

    經(jīng)常需要提供接口與用戶交互(獲取數(shù)據(jù)、上傳數(shù)據(jù)等),由于這個(gè)過程需要用戶進(jìn)行相關(guān)的操作,為了避免出現(xiàn)一些錯(cuò)誤的數(shù)據(jù)等,一般需要對數(shù)據(jù)進(jìn)行校驗(yàn),下面這篇文章主要給大家介紹了關(guān)于SpringBoot各種參數(shù)校驗(yàn)的相關(guān)資料,需要的朋友可以參考下
    2022-05-05
  • Java數(shù)據(jù)類型、運(yùn)算符和方法重點(diǎn)總結(jié)大全

    Java數(shù)據(jù)類型、運(yùn)算符和方法重點(diǎn)總結(jié)大全

    在大學(xué)Java編程課程中,數(shù)據(jù)類型和運(yùn)算符是構(gòu)建程序設(shè)計(jì)邏輯的基石,這篇文章主要介紹了Java數(shù)據(jù)類型、運(yùn)算符和方法重點(diǎn)總結(jié)的相關(guān)資料,文中通過代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2026-02-02
  • 詳解如何有效地處理Java中的多線程

    詳解如何有效地處理Java中的多線程

    在現(xiàn)代軟件開發(fā)中,多線程編程已成為提高程序性能和響應(yīng)速度的重要手段,Java提供了豐富的多線程支持,使得在Java中實(shí)現(xiàn)并發(fā)操作變得相對簡單,本文將深入探討Java多線程編程的基本概念、常見問題和最佳實(shí)踐,需要的朋友可以參考下
    2024-06-06

最新評論

南充市| 依安县| 陇南市| 通许县| 白朗县| 彰武县| 慈利县| 清镇市| 松桃| 天长市| 桂阳县| 沾益县| 桃园市| 礼泉县| 澳门| 怀宁县| 平度市| 田东县| 邵东县| 内黄县| 曲沃县| 尉犁县| 雅江县| 安庆市| 呈贡县| 资溪县| 连城县| 伊金霍洛旗| 加查县| 岱山县| 普兰店市| 藁城市| 无棣县| 沁源县| 大英县| 磐石市| 犍为县| 江华| 马鞍山市| 道孚县| 扎赉特旗|