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

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ū)分。

一、簡單工廠

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

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

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

假設(shè)我們有如下場景,我們需要根據(jù)配置文件的后綴(json、xml、yaml、properties)選擇不同的解析器,將存儲(chǔ)在文件中的配置解析成內(nèi)存對(duì)象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;
  }
}

對(duì)于上面兩種簡單工廠模式的實(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)的能力,對(duì)簡單工廠進(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)來看,工廠類對(duì)象的創(chuàng)建邏輯又耦合進(jìn)了 load() 函數(shù)中,跟我們最初的代碼版本非常相似,引入工廠方法非但沒有解決問題,反倒讓設(shè)計(jì)變得更加復(fù)雜了。那怎么來解決這個(gè)問題呢?

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

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

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

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

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

四、抽象工廠

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

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

  • JsonRuleConfigParser
  • XmlRuleConfigParser
  • YamlRuleConfigParser
  • PropertiesRuleConfigParser

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

  • JsonSystemConfigParser
  • XmlSystemConfigParser
  • YamlSystemConfigParser
  • PropertiesSystemConfigParser

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

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

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

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

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

這樣就可以有效地減少工廠類的個(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í)候,我們就考慮使用工廠模式,封裝對(duì)象的創(chuàng)建過程,將對(duì)象的創(chuàng)建和使用相分離。

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

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

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

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

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

相關(guān)文章

  • Springboot2.6.x的啟動(dòng)流程與自動(dòng)配置詳解

    Springboot2.6.x的啟動(dòng)流程與自動(dòng)配置詳解

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

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

    在Java開發(fā)中,通常會(huì)采用三層架構(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ā)的?個(gè)輕量級(jí)RESTful的HTTP服務(wù)客戶端(?它來發(fā)起請(qǐng)求,遠(yuǎn)程調(diào)?的),是以Java接?注解的?式調(diào)?Http請(qǐng)求,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)識(shí)bean是否需要延遲加載,沒加注解之前主要容器啟動(dòng)就會(huì)實(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ì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(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的一個(gè)集成框架,是目前較流行的一種web應(yīng)用程序開源框架。本文給大家詳細(xì)看一下組成SSH的這三個(gè)框架
    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í)題(分享)。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧,希望可以幫到你
    2021-07-07

最新評(píng)論