亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

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

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

前言

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

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

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

一、簡(jiǎn)單工廠

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

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

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

假設(shè)我們有如下場(chǎng)景,我們需要根據(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;
  }
}

另外一種簡(jiǎn)單工廠的實(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全憑你自己說(shuō)了算
    }
    IRuleConfigParser parser = cachedParsers.get(configFormat.toLowerCase());
    return parser;
  }
}

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

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

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

二、工廠方法(Factory Method)

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

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

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

我們可以為工廠類(lèi)再創(chuàng)建一個(gè)簡(jiǎn)單工廠,也就是工廠的工廠,用來(lái)創(chuàng)建工廠類(lèi)對(duì)象。這段話聽(tīng)起來(lái)有點(diǎn)繞,我把代碼實(shí)現(xiàn)出來(lái)了,你一看就能明白了。其中,RuleConfigParserFactoryMap 類(lèi)是創(chuàng)建工廠對(duì)象的工廠類(lèi),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類(lèi)只包含方法,不包含成員變量,完全可以復(fù)用,
//不需要每次都創(chuàng)建新的工廠類(lèi)對(duì)象,所以,簡(jiǎn)單工廠模式的第二種實(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)用場(chǎng)景來(lái)說(shuō),工廠模式需要額外創(chuàng)建諸多 Factory 類(lèi),也會(huì)增加代碼的復(fù)雜性,而且,每個(gè) Factory 類(lèi)只是做簡(jiǎn)單的 new 操作,功能非常單薄(只有一行代碼),也沒(méi)必要設(shè)計(jì)成獨(dú)立的類(lèi),所以,在這個(gè)應(yīng)用場(chǎng)景下,簡(jiǎn)單工廠模式簡(jiǎn)單好用,比工廠方法模式更加合適。

三、如何選擇使用簡(jiǎn)單工廠和工廠方式

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

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

四、抽象工廠

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

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

  • JsonRuleConfigParser
  • XmlRuleConfigParser
  • YamlRuleConfigParser
  • PropertiesRuleConfigParser

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

  • JsonSystemConfigParser
  • XmlSystemConfigParser
  • YamlSystemConfigParser
  • PropertiesSystemConfigParser

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

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

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

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

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

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

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

 
public interface IConfigParserFactory {
  IRuleConfigParser createRuleParser();
  ISystemConfigParser createSystemParser();
  //此處可以擴(kuò)展新的parser類(lèi)型,比如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)建過(guò)程,將對(duì)象的創(chuàng)建和使用相分離。

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

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

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

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

到此這篇關(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)資料,文中通過(guò)實(shí)例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2022-01-01
  • Java中Controller、Service、Dao/Mapper層的區(qū)別與用法

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

    在Java開(kāi)發(fā)中,通常會(huì)采用三層架構(gòu)(或稱(chēng)MVC架構(gòu))來(lái)劃分程序的職責(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框架開(kāi)發(fā)圖書(shū)借閱系統(tǒng)源代碼

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

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

    Spring Cloud Feign的使用案例詳解

    Feign是Netflix開(kāi)發(fā)的?個(gè)輕量級(jí)RESTful的HTTP服務(wù)客戶端(?它來(lái)發(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是否需要延遲加載,沒(méi)加注解之前主要容器啟動(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)步驟,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2023-08-08
  • SpringBoot操作spark處理hdfs文件的操作方法

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

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

    SSH 框架簡(jiǎn)介

    SSH是 struts+spring+hibernate的一個(gè)集成框架,是目前較流行的一種web應(yīng)用程序開(kāi)源框架。本文給大家詳細(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ī)?lái)一篇Java基礎(chǔ)的幾道練習(xí)題(分享)。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧,希望可以幫到你
    2021-07-07

最新評(píng)論