摘要:需要說明的是在設計模式一書中將工廠模式分為兩類工廠方法模式與抽象工廠模式,將簡單工廠模式看為工廠方法模式的一種特例,兩者歸為一類。工廠模式的作用工廠模式的作用封裝變化創建邏輯有可能變化,封裝成工廠類之后,創建邏輯的變更對調用者透明。
Define an interface for creating an object,but let subclasses decide which class toinstantiate.Factory Method lets a class defer instantiation to subclasses.
定義一個創建對象的接口,讓其子類自己決定實例化哪一個工廠類,工廠模式使其創建過程延遲到子類進行。
說人話:提供創建對象的接口,將創建對象的過程屏蔽,從而達到靈活的目的。
一般情況下,工廠模式分為三類:
①、簡單工廠模式(Simple Factory)
②、工廠方法模式(Factory Method)
③、抽象工廠模式(Abstract Factory)
這三種模式從上到下逐步抽象,并且更具一般性。
需要說明的是:GOF 在《設計模式》一書中將工廠模式分為兩類:工廠方法模式(Factory Method)與抽象工廠模式(Abstract Factory),將簡單工廠模式(Simple Factory)看為工廠方法模式的一種特例,兩者歸為一類。
下面我們分別介紹這三種工廠模式。
比如有這樣一個需求:
根據導入的不同文件(docx,xlsx,pptx),選擇不同的解析器進行解析。
簡單工廠有三個核心對象:
1.工廠:簡單工廠模式的核心,它負責實現創建所有實例的內部邏輯。工廠類的創建產品類的方法可以被外界直接調用,創建所需的產品對象。
2.抽象產品 :簡單工廠模式所創建的所有對象的父類,它負責描述所有實例所共有的公共接口。
3.具體產品:是簡單工廠模式的創建目標,所有創建的對象都是充當這個角色的某個具體類的實例。
①、抽象解析器
public interface IOfficeParser { void parse();}
②、具體解析器(docx,xlsx,pptx)
public class WordParser implements IOfficeParser{ private String filePath; public WordParser(String filePath){ this.filePath = filePath; } @Override public void parse() { System.out.println("解析 docx 文件"); }}
public class ExcelParser implements IOfficeParser{ private String filePath; public ExcelParser(String filePath){ this.filePath = filePath; } @Override public void parse() { System.out.println("解析 xlsx 文件"); }}
public class PptParser implements IOfficeParser { private String filePath; public PptParser(String filePath){ this.filePath = filePath; } @Override public void parse() { System.out.println("解析 pptx 文件"); }}
③、構造解析器的工廠
public class OfficeParserFactory { public static IOfficeParser getParser(String filePath) throws Exception { String fileExtension = getFileExtension(filePath); IOfficeParser parser = null; if("docx".equalsIgnoreCase(fileExtension)){ parser = new WordParser(filePath); }else if("xlsx".equalsIgnoreCase(fileExtension)){ parser = new ExcelParser(filePath); }else if("pptx".equalsIgnoreCase(fileExtension)){ parser = new PptParser(filePath); }else{ throw new Exception("file is not supported:"+fileExtension); } return parser; } private static String getFileExtension(String filePath){ // 解析文件名獲取文件擴展名,比如 文檔.docx,返回 docx String fileExtension = filePath.substring(filePath.lastIndexOf(".")+1); return fileExtension; }}
④、測試類
public class SimpleFactoryTest { public static void main(String[] args) throws Exception { String filePath = "文檔.docx"; IOfficeParser parser = OfficeParserFactory.getParser(filePath); parser.parse(); String filePath1 = "表格.xlsx"; IOfficeParser parser1 = OfficeParserFactory.getParser(filePath1); parser1.parse(); }}
⑤、總結
這便是簡單工廠,客戶端避免了直接創建解析器的責任,只需要調用工廠類去解析就行了。
可以從開閉原則(對擴展開放,對修改關閉)來分析簡單工廠模式:當增加一種文件解析,比如老版本的 doc 格式。這時候只需要新增一個 parser 類即可,客戶端(理解為測試類,調用端)不用改變,然后在工廠類 OfficeParserFactory 新增一個 else-if 分支即可。
這時候可能有同學會問了,那修改了 OfficeParserFactory 類,不就違反開閉原則了嗎?但其實只要不是頻繁的添加新的 parser,偶爾修改一下 OfficeParserFactory 類,稍微不符合開閉原則,也是可以接受的。
看上去比較完美,細心的同學可能會問,所有的解析類對象創建都在 OfficeParserFactory 類中,假設某個解析類,比如 doc 創建parser 對象并不是簡單的 new ,還包括一些其它的操作,這時候難道把這些代碼也全部寫到 OfficeParserFactory 中嗎?有沒有更優雅的寫法呢?
有,就是下面要介紹的 工廠模式。
為了解決上面的問題,我們可以為工廠類在創建一個工廠,也就是工廠的工廠,用來創建工廠類對象。
①、給每一個具體解析器創建工廠
public class ExcelParserFactory implements IOfficeParserFactory { @Override public IOfficeParser createParser() { // TODO 進行創建對象的一些操作 return new ExcelParser(); }}
②、創建解析器的工廠
public class OfficeParserFactory { public static IOfficeParser getParser(String filePath) throws Exception { String fileExtension = getFileExtension(filePath); IOfficeParserFactory parserFactory = OfficeParserFactoryMap.getOfficeParseFactory(fileExtension); if(parserFactory == null){ throw new Exception("file is not supported:"+fileExtension); } IOfficeParser parser = parserFactory.createParser(); return parser; } private static String getFileExtension(String filePath){ // 解析文件名獲取文件擴展名,比如 文檔.docx,返回 docx String fileExtension = filePath.substring(filePath.lastIndexOf(".")+1); return fileExtension; }}
③、創建解析器工廠的工廠類
public class OfficeParserFactoryMap { private static final Map parserFactoryCached = new HashMap<>(); static { parserFactoryCached.put("docx",new WordParserFactory()); parserFactoryCached.put("xlxs",new ExcelParserFactory()); parserFactoryCached.put("pptx",new PptParserFactory()); } public static IOfficeParserFactory getOfficeParseFactory(String type){ if(type == null || type.isEmpty()){ return null; } return parserFactoryCached.get(type.toLowerCase()); }}
④、測試類
public class FactoryTest { public static void main(String[] args) throws Exception { String filePath = "文檔.docx"; IOfficeParser parser = OfficeParserFactory.getParser(filePath); parser.parse(); }}
⑤、總結
在工廠模式中,如果我們要增加新的文件解析,比如 mdb 格式(office access套件),就只需要創建新的 parser 類和 parserFactory 類,并且在 OfficeParserFactoryMap 類中將新的 parserFactory 類添加到 map 中即可。代碼的改動非常少,基本上是符合開閉原則的。
但是,我們看到工廠模式新增了很多 factory 類,會增加代碼的復制性,如果每個 factory 類只是做簡單的 new 操作,則沒必要使用該模式,直接用簡單工廠模式即可。
這種模式比較特殊,使用場景不多,大家簡單了解一下就行。
我們知道 doc 和 docx 都是 office word 文檔后綴,類似 xls 和 xlsx 都是 office Excel 表格后綴,還有 ppt 和 pptx。doc/xlx/ppt 都是舊版本 office 文件后綴,都是二進制組成,解析的時候有共同之處,而 docx/xlsx/pptx 是office新版本文件后綴,是通過 ooxml 結構組成。相當于一組是老的office,一組是新的office。
如果我們還是用工廠模式來實現的話,那每一種都要編寫一個工廠類,過多的類會難以維護,那怎么解決呢?
抽象工廠模式就是針對這種特殊的場景誕生,我們可以讓一個工廠復制創建多個不同類型的對象,而不是只創建一個 parser 對象。
具體代碼實現如下:
public interface IOfficeParserFactory { IOfficeParser createParser(); IOldOfficeParser createOldParser();}
public class ExcelParserFactory implements IOfficeParserFactory { @Override public IOfficeParser createParser() { return new ExcelParser(); } @Override public IOldOfficeParser createOldParser() { return new DocParser(); }}
簡單工廠:將創建不同對象的邏輯放在一個工廠類中。
工廠方法:將創建不同對象的邏輯放在不同工廠類中,先用一個工廠類的工廠類得到某個工廠,在某這個工廠來創建對象。
這樣講區別就很明顯了,如果創建對象的邏輯比較復雜,要做各種初始化操作,這時候使用工廠方法,能夠將復雜的創建邏輯拆分到多個工廠類中;而創建對象的邏輯很簡單,就沒必要額外創建多個工廠類,直接使用簡單工廠即可。
封裝變化:創建邏輯有可能變化,封裝成工廠類之后,創建邏輯的變更對調用者透明。
代碼復用:創建代碼抽離到獨立的工廠類之后可以復用。
隔離復雜性:封裝復雜的創建邏輯,調用者無需了解如何創建對象。
控制復雜度:將創建代碼抽離出來,讓原本的函數或類職責更單一,代碼更簡潔。
看完知道為啥沒事別用工廠模式了吧,因為太好用了,你會愛上它的。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/123759.html
摘要:強大的表單驗證前端掘金支持非常強大的內置表單驗證,以及。面向對象和面向過程的區別的種設計模式全解析后端掘金一設計模式的分類總體來說設計模式分為三大類創建型模式,共五種工廠方法模式抽象工廠模式單例模式建造者模式原型模式。 強大的 Angular 表單驗證 - 前端 - 掘金Angular 支持非常強大的內置表單驗證,maxlength、minlength、required 以及 patt...
摘要:我們今天也來做一個萬能遙控器設計模式適配器模式將一個類的接口轉換成客戶希望的另外一個接口。今天要介紹的仍然是創建型設計模式的一種建造者模式。設計模式的理論知識固然重要,但 計算機程序的思維邏輯 (54) - 剖析 Collections - 設計模式 上節我們提到,類 Collections 中大概有兩類功能,第一類是對容器接口對象進行操作,第二類是返回一個容器接口對象,上節我們介紹了...
摘要:與以往的使用的方式不同,工廠模式使用工廠實例化對象。抽象工廠模式亮相抽象工廠模式抽象工廠模式提供一個接口,用于創建相關或依賴對象的家族,而不需要明確指定具體類。 寫在前面 這篇博文介紹設計模式的形式將與其他篇博文不太一樣,這里我們將從一個問題入手,逐步了解到簡單工廠、工廠方法與抽象工廠模式。 PS:這篇博文涉及的內容較多,所以篇幅有點長,請耐心閱讀。 為什么要使用工廠模式? 在 OO ...
摘要:我認為按書上的順序比較好理解因為簡單靜態工廠模式是在工廠方法模式上縮減,抽象工廠模式是在工廠方法模式上再增強。所以我就先講工廠方法模式了。抽象工廠模式抽象工廠模式就比較復雜了,我們一般的應用都寫不到。 前言 只有光頭才能變強 回顧前面: 給女朋友講解什么是代理模式 包裝模式就是這么簡單啦 單例模式你會幾種寫法? 昨天寫了單例模式了,今天是時候寫工廠模式啦~ 工廠模式我個人認為其實比...
閱讀 3022·2021-11-18 10:07
閱讀 3764·2021-11-17 17:00
閱讀 2103·2021-11-15 18:01
閱讀 926·2021-10-11 10:58
閱讀 3372·2021-09-10 10:50
閱讀 3442·2021-08-13 15:05
閱讀 1229·2019-08-30 15:53
閱讀 2639·2019-08-29 13:01