电脑知识|欧美黑人一区二区三区|软件|欧美黑人一级爽快片淫片高清|系统|欧美黑人狂野猛交老妇|数据库|服务器|编程开发|网络运营|知识问答|技术教程文章 - 好吧啦网

您的位置:首頁技術文章
文章詳情頁

詳解Java從工廠方法模式到 IOC/DI思想

瀏覽:91日期:2022-08-11 14:45:00
目錄前言工廠方法模式工廠方法的結構工廠方法模式的樣例代碼工廠方法模式實現(xiàn)文件導出工廠方法與簡單工廠的區(qū)別工廠方法模式的意義工廠方法模式與IOC、DI什么是IOC/DI?工廠方法與IOC/DI思想前言

簡單工廠的本質(zhì)是選擇實現(xiàn),說白了是由一個專門的類去負責生產(chǎn)我們所需要的對象,從而將對象的創(chuàng)建從代碼中剝離出來,實現(xiàn)松耦合。我們來看一個例子:

我們要創(chuàng)建一個文件導出工具

public interface FileOper{ public Boolean exceptFile(String data);}public class XMLFileOp implment FileOper{ public Boolean exceptFile(String data){ System.out.println('導出一個xml文件'); return true; } }public class Factory{ public static FileOper createFileOp(){return new XMLFileOp(); } }public Class Test{ public static void main(String args[]){ FileOper op = Factory.createFileOp(); op.exceptFile('測試');}}

這樣看起來沒什么問題,那么我們既然做出來了這個結構,就是為了后續(xù)的擴展它,例子中只是為了實現(xiàn)XML文件的導出,后續(xù),我們可以自己實現(xiàn)一個txt文件的導出類,只需要實現(xiàn)FileOper接口就好:

public Class TxtFileOp implment FileOper{ public Boolean ExceptFile(String data){ System.out.println('導出txt文件'); return true; } }

這時候我們還是通過工廠來獲取這個對象,只需將Factory中追加一個else if 即可通過傳參來獲取想要的對象了。

工廠方法模式

仔細分析上面的場景,事實上在實現(xiàn)導出文件的業(yè)務邏輯中,它根本不知道要使用哪一種導出文件的格式,因此這個對象根本就不應該和具體導出文件的對象耦合在一起,它只需要面向導出文件接口(FileOper)就好,這是工廠的思想,我們上面用簡單工廠沒錯啊,但是后面又加入了新的擴展

這樣一來,又有新的問題,面對新的類,簡單工廠便不能提供動態(tài)的擴展,必須要去修改內(nèi)部的代碼,破壞了開閉原則。我們上一篇也提到了,簡單工廠也有它自身的缺陷,其中最嚴重的就是,它雖然對依賴對象的主體實現(xiàn)了解耦,可是它本身內(nèi)部卻耦合較為嚴重。這時候我們可以看看工廠方法模式了,工廠方法模式的思路很有意思:老子不管了!采取無為而治的方式。不是需要接口對象么,那就定義一個方法來創(chuàng)建,可是事實上它自己是不知道如何創(chuàng)建這個接口對象的,不過這不重要,定義成抽象方法就行了,交給子類去實現(xiàn),老子欠債,兒子你來還。

工廠方法的結構

詳解Java從工廠方法模式到 IOC/DI思想

Product:工廠方法所創(chuàng)建的具體對象的統(tǒng)一接口。

Factory:為該類產(chǎn)品的抽象工廠,其內(nèi)部有聲明的工廠方法,工廠方法多為抽象方法,且返回一個Product對象

ProductOne:為具體的產(chǎn)品,也就是Product的具體實現(xiàn)類,真正的工廠產(chǎn)物。

SpecificFactory:具體的工廠,用于生產(chǎn)指定類型的Product,例如圖中它只負責生產(chǎn) ProductOne這個對象。

工廠方法模式的樣例代碼

public class AbstractFactoryTest { public static void main(String[] args) {try { Product a; AbstractFactory af; af = (AbstractFactory) ReadXML1.getObject(); a = af.newProduct(); a.show();} catch (Exception e) { System.out.println(e.getMessage());} }}//抽象產(chǎn)品:提供了產(chǎn)品的接口interface Product { public void show();}//具體產(chǎn)品1:實現(xiàn)抽象產(chǎn)品中的抽象方法class ConcreteProduct1 implements Product { public void show() {System.out.println('具體產(chǎn)品1顯示...'); }}//具體產(chǎn)品2:實現(xiàn)抽象產(chǎn)品中的抽象方法class ConcreteProduct2 implements Product { public void show() {System.out.println('具體產(chǎn)品2顯示...'); }}//抽象工廠:提供了廠品的生成方法interface AbstractFactory { public Product newProduct();}//具體工廠1:實現(xiàn)了廠品的生成方法class ConcreteFactory1 implements AbstractFactory { public Product newProduct() {System.out.println('具體工廠1生成-->具體產(chǎn)品1...');return new ConcreteProduct1(); }}//具體工廠2:實現(xiàn)了廠品的生成方法class ConcreteFactory2 implements AbstractFactory { public Product newProduct() {System.out.println('具體工廠2生成-->具體產(chǎn)品2...');return new ConcreteProduct2(); }}

基于XML解析的外部配置文件

class ReadXML1 { //該方法用于從XML配置文件中提取具體類類名,并返回一個實例對象 public static Object getObject() {try { //創(chuàng)建文檔對象 DocumentBuilderFactory dFactory = DocumentBuilderFactory.newInstance(); DocumentBuilder builder = dFactory.newDocumentBuilder(); Document doc; doc = builder.parse(new File('src/FactoryMethod/config1.xml')); //獲取包含類名的文本節(jié)點 NodeList nl = doc.getElementsByTagName('className'); Node classNode = nl.item(0).getFirstChild(); String cName = 'FactoryMethod.' + classNode.getNodeValue(); //System.out.println('新類名:'+cName); //通過類名生成實例對象并將其返回 Class<?> c = Class.forName(cName); Object obj = c.newInstance(); return obj;} catch (Exception e) { e.printStackTrace(); return null;} }}

上面是一個較為初級也較為經(jīng)典的工廠方法模板,工廠方法還有另一種用法,即抽象的工廠父類除了創(chuàng)建對象的方法之外,還包含其他的一些方法,而工廠父類通常使用這些方法來完成某些任務,下面我們來看看這第二種表現(xiàn)方式。

工廠方法模式實現(xiàn)文件導出

根據(jù)上面工廠方法模式提供的思路,我們重新來思考并實現(xiàn)一下一開始那個文件導出的功能。

/** * 文件導出接口 * 實現(xiàn)將指定數(shù)據(jù)的導出 * 擴展:實現(xiàn)該接口,可指定生產(chǎn)具體文件類型 * @author GCC */public interface ExportFileApi { /** * 導出文件 * @param data 待導出數(shù)據(jù) * @return boolean */ boolean exportFile(String data);}/** * 生產(chǎn)Excel文件導出器 * @author GCC */public class ExportExcelFile implements ExportFileApi { @Override public boolean exportFile(String data) {//todo 處理數(shù)據(jù)return false; }}/** * 導出功能口,工廠 * @author GCC */public abstract class ExportFileOperate { public Logger logger = Logger.getLogger(ExportFileOperate.class); //使用產(chǎn)品對象來實現(xiàn)一定功能的方法,這里是實現(xiàn)數(shù)據(jù)導出 public void export(String data){ExportFileApi exportoper = methodFactory();if(exportoper.exportFile(data)){ logger.info('文件導出成功'); return;}logger.error('文件導出失敗'); } //工廠方法 protected abstract ExportFileApi;}/** * 將指定數(shù)據(jù)導出為Excel文件 * @author GCC */public class ExportExcelFileFactory extends ExportFileOperate { @Override protected ExportFileApi methodFactory() {return new ExportExcelFile(); }}/** * 客戶用例 */public class App { static Logger logger = Logger.getLogger(App.class); public static void main( String[] args ) {ExportFileOperate ex = new ExportExcelFileFactory();ex.export('測試數(shù)據(jù)'); }}

這里大家可能會 有疑惑,你這個實現(xiàn)方式怎么和前面提到的工廠方法模式的標準樣例不一樣? 其實這是工廠方法模式的另一種結構,確切地說這才是真正意義上的工廠方法模式(上面的模板只是工廠方法的正常形態(tài))。

這一種的實現(xiàn)方式是 :父類會是一個抽象類,里面包含創(chuàng)建所需對象的抽象方法(代碼樣例中ExportFileOperat類的methodFactory()方法,這里ExportFileOperat類就是所謂的工廠類,需要補充的是設計模型的使用,不要拘泥于命名名稱,可以根據(jù)實際需求來進行相應的變化),這些抽象方法就是工廠方法模式中的工廠方法。父類里面,通常會有使用這些產(chǎn)品對象來實現(xiàn)一定的功能的方法(代碼樣例中ExportFileOperat類的export()方法)。而這些方法所實現(xiàn)的功能通常都是公共功能,不管子類選擇了何種具體的產(chǎn)品實現(xiàn),這些方法總能正常運行。

之所以會有上面兩種方式,主要原因在于工廠方法對于客戶端的支持,這里需要弄清楚一個問題,誰在使用工廠方法所創(chuàng)建的對象?

事實上,在工廠方法模式里,應該是工廠中的其他方法來使用工廠所創(chuàng)建的對象,為了方便,工廠方法創(chuàng)建的對象也可直接提供給外部的客戶端來調(diào)用,但工廠方法的本意是由Factory抽象父類內(nèi)部的方法來使用工廠方法創(chuàng)建的對象。

以下這幅時序圖,即說明了客戶端調(diào)用factory的兩種方式。

詳解Java從工廠方法模式到 IOC/DI思想

其實客戶端應該使用Factory對象,或者是由Factory所創(chuàng)建出來的產(chǎn)品對象,對于客戶端使用Factory對象,這個時候工廠方法創(chuàng)建的對象,是Factory中的某些方法在用,對于使用那些由Factory創(chuàng)建出來的對象,這個時候工廠方法創(chuàng)建的對象,是構成客戶端所需對象的一部分。

工廠方法與簡單工廠的區(qū)別

下面我們看一個例子,這里我打算做個計算器,如果用簡單工廠模式來做,它的結構是這樣的:

詳解Java從工廠方法模式到 IOC/DI思想

public class SimpleFactory { public Calculator create(String type){switch (type){ case '+'://返回一個具有加法功能的計算器對象return new AddCalculator(); case '-'://返回一個具有減法功能的計算器對象return new DeCalculator(); default:return null;} }}

為了工廠更完整,采用傳參的靜態(tài)工廠方式來實現(xiàn),這樣我簡單工廠里將通過Switch語句來管控生產(chǎn)哪一種計算類,這時候,突然來了新的需求,我需要一個乘法的功能,這時候我就得實現(xiàn)計算器接口,完成一個乘法類,同時去簡單工廠的代碼里,追加一個case。

詳解Java從工廠方法模式到 IOC/DI思想

同理,我使用工廠方法的模式來做這個功能,這塊的類圖則如上圖一樣,我的工廠代碼里不需要Switch了,只需要一個具有生產(chǎn)計算器對象的抽象方法的抽象工廠類即可,當我需要一個乘法能力的計算器時,實現(xiàn)計算器接口,完成乘法類,然后繼承抽象工廠,完成一個乘法的工廠子類,然后再用乘法的工廠子類來創(chuàng)建乘法類。然后再去修改客戶端。

上面一對比,嘿,這升級版的工廠方法怎么比簡單工廠還復雜了!?肯定很多同學在看工廠設計模式的時候很困惑,簡單工廠和工廠方法的區(qū)別在哪,明明感覺用簡單工廠更方便呢?

其實回頭好好看看設計原則,就會發(fā)現(xiàn),這是一個解耦的過程,簡單工廠模式最大的優(yōu)點在于工廠類中包含了必要的邏輯判斷,根據(jù)客戶的選擇動態(tài)的實例化相關的產(chǎn)品類,對于客戶端來說,除去了與具體產(chǎn)品對象的依賴。但問題就是隨著你的新需求,如果使用簡單工廠,那么你就不得不去破壞開閉原則,而看起來改動更為復雜的工廠方法模式,你并不需要對以前的代碼進行改動,只需要繼承,擴展即可。仔細觀察一下,簡單工廠是讓客戶端與依賴對象進行解耦,而工廠方式模式又是對工廠的一層解耦,原本內(nèi)部耦合性較強的if else,變成了由客戶端或者配置文件來控制,工廠方法將簡單工廠內(nèi)部的邏輯判斷移到了使用它的外部(客戶端或者配置文件)來控制。本來擴展是需要修改工廠類源代碼的,現(xiàn)在變成了客戶端修改調(diào)用或者配置文件中的一個參數(shù)。

工廠方法模式的意義

工廠方法模式的主要思想是讓父類在不知情的情況下,完成自身功能的調(diào)用,而具體的實現(xiàn)則延遲到子類來做;或者說是在靜態(tài)工廠中,將其原本耦合的if else抽離出來,配合配置文檔使用,將寫死的if else靈活實現(xiàn)(配置文件并不是默認必須要有的)。這樣在設計的時候,不用去考慮具體的實現(xiàn),需要某個對象,把它通過工廠方法返回就好,在使用這些對象實現(xiàn)功能的時候還是通過接口來操作,這里就有一點IOC的韻味了。

工廠方法模式與IOC、DI什么是IOC/DI?

想想之前沒有學習設計模式,剛學會使用Java就被Spring的bean配置文件支配的恐懼。

那時候你說自己學Java,對方一定會問你Spring,說到Spring,肯定避不開“什么是IOC,什么是DI?”這個讓人頭痛的問題,那么,到底什么是IOC,DI?

看完工廠的設計思想,對這個問題才開始了真正的思考。

IOC——控制反轉

DI——依賴注入

除了上面脫口而出的回答,我想我們這些面向對象的程序猿們,應該有個更深入的理解,到底什么是控制反轉,什么是依賴注入。要想理解上面兩個概念,必須把問題拆開來看,先搞清楚基本的問題幾個問題:

主客體是誰,或者說參與這個概念的都有誰?

什么叫依賴?為什么會有依賴?

什么叫注入?注入的是什么?誰注入誰?

控制反轉,誰控制誰,控制的是什么,既然叫反轉,正轉是啥?

下面我們一個個來解決問題:

1、參與者,說起參與者,一般我們在這個概念中是有三個參與者,具體某個類,容器,某個對象所依賴的外部資源(另一個對象),就好比我有三個類,A,B,C,A對象我們把它想象成一個客戶端,B是它需要的一個外部的資源,C是一個叫容器的第三方。

2、什么叫依賴,這個就比較好說了,你有一個A類,但是你A類的成員變量有一個是B類的實例聲明,那么A就依賴于B,也就是說,A如果想正常運轉(或者說功能正常),必須得依賴于它的成員變量B,至于為什么會有依賴,那也好理解了,面向對象就是將功能封裝,每個對象都功能單一,這樣有些復雜的對象需要實現(xiàn)復雜的功能,就必須需要其他類的協(xié)同。

3、注入,就是說,A你的成員變量B只是聲明了一個變量,它對于對象A來說,只是一個引用,一個字符,本身并沒有實體,你可以new 一下這個變量的構造函數(shù),才能使這個變量真正有靈魂,又或者用它來承接外部傳進來的同類實體,這里外部傳進來B的方式就叫注入,注入的是這個變量類型 具體的實例化對象。誰來注入,當然是容器C來注入給A,將B注入給A

4、簡單來說就是容器來控制A,控制的就是A所依賴的對象B實例的創(chuàng)建,反轉是與正轉對應來說的,什么是正轉呢,A類中有個對象B的成員變量,正常情況下,A類中功能用到B對象的時候,A要主動去獲取一個B對象,例如new一下,這種情況被稱為正向的。這樣就比較好理解反轉了,A不再去主動獲取B對象了,而是被動的等待B的到來(注入),等待容器C獲取一個B的實例,然后反向的注入進A。

詳解Java從工廠方法模式到 IOC/DI思想

所以,綜上來看,控制反轉和依賴注入其實說的是同一件事,說白了就是對象創(chuàng)建這個責任歸誰的問題,依賴注入是從應用程序的角度去描述,應用程序依賴外部容器去創(chuàng)建并注入它所需要的外部資源對象。控制反轉是從容器的角度出發(fā),容器控制應用程序,由容器反向地向應用程序注入其所需要的外部對象。

其實IOC/DI并不是一種代碼實現(xiàn),更多的它是一種思想,它從思想上完成了 “主從換位” 的變化,應用程序本來是主體,占絕對地位,它需要什么都會主動出擊去獲取,過強的控制欲導致了它耦合過重,而在IOC/DI思想中,應用程序變成被動的等待容器的注入,需要啥只能提出來,什么時候給,給什么樣子的,主動權完全交給了容器,較強的實現(xiàn)了解耦,程序的靈活性也就高了

工廠方法與IOC/DI思想

從某個角度來看,工廠方法模式跟IOC/DI的思想很貼近。

上面也說過了,IOC/DI就是讓應用程序不再主動獲取外部資源,而是被動等待第三方的注入,那么在編寫程序的時候,一旦遇到需要外部資源的地方,就會開一個窗口,提供給容器一個注入的途徑,讓容器注入進來,細節(jié)這里就不過多贅述了,自己去找Spring聊吧。 下面用IOC/DI和工廠方法來實現(xiàn)一個樣例對比一下。

用IOC/DI來實現(xiàn)一個類Person:

public class Person { private String name; //依賴文件操作對象 private FileUtil fileUtil; private int age; //提供set方法,供外部注入 public void setFileUtil(FileUtil fileUtil){this.fileUtil = fileUtil; }public void opFile(String fileurl){fileUtil.createFile(fileurl); } }

這就是IOC/DI思想來實現(xiàn)的一個類,我依賴FileUtil,沒事,我不管,我提供給你一個set的注入途徑,剩下的我不管了,我就默認我用FileUtil的時候,它是真真切切存在在堆中的對象。(本質(zhì)是當外部的容器,創(chuàng)建Person對象的時候,會發(fā)現(xiàn)它依賴FileUtil,然后容器去獲取一個FileUtil,通過Person提供的Set方法,將獲取的FileUtil對象注入進去,然后一個完整的Person對象就被制造出來了,這個過程Person角度來看,Person是無感的)

下面用工廠方法來搞上面的例子:

public abstract class Person { private String name; private int age; //交給子類去實現(xiàn)我的依賴 public abstract FileUtil getFileutil(); public void opFile(String fileurl){getFileutil().createFile(fileurl); }}

這里,Person類也是需要用到FileUtil,但是它也不需要主動的去new一下FileUtil,而是通過抽象方法的形式,將FileUtil的實例化延申到子類去實現(xiàn),其實就是變相地提供了一種注入渠道(標準bean中是通過set方法,容器調(diào)用Set方法注入需要的對象,而工廠方法則是通過實現(xiàn)子類,即讓子類來完成依賴對象的注入)

仔細體會這兩種寫法,對比他們的實現(xiàn),在思想層面來看,會發(fā)現(xiàn),工廠方法模式和IOC/DI的思想是相似的,都是“主動變被動”,“主位換從位”,從而獲得了更加靈活的程序結構。

以上就是詳解Java從工廠方法模式到 IOC/DI思想的詳細內(nèi)容,更多關于Java從工廠方法模式到 IOC/DI思想的資料請關注好吧啦網(wǎng)其它相關文章!

標簽: Java
相關文章:
主站蜘蛛池模板: 无锡网站建设_小程序制作_网站设计公司_无锡网络公司_网站制作 | 无线联网门锁|校园联网门锁|学校智能门锁|公租房智能门锁|保障房管理系统-KEENZY中科易安 | SOUNDWELL 编码器|电位器|旋转编码器|可调电位器|编码开关厂家-广东升威电子制品有限公司 | 环氧乙烷灭菌器_压力蒸汽灭菌器_低温等离子过氧化氢灭菌器 _低温蒸汽甲醛灭菌器_清洗工作站_医用干燥柜_灭菌耗材-环氧乙烷灭菌器_脉动真空压力蒸汽灭菌器_低温等离子灭菌设备_河南省三强医疗器械有限责任公司 | HYDAC过滤器,HYDAC滤芯,现货ATOS油泵,ATOS比例阀-东莞市广联自动化科技有限公司 | 阴离子_阳离子聚丙烯酰胺厂家_聚合氯化铝价格_水处理絮凝剂_巩义市江源净水材料有限公司 | 标策网-专注公司商业知识服务、助力企业发展 | 冲锋衣滑雪服厂家-冲锋衣定制工厂-滑雪服加工厂-广东睿牛户外(S-GERT) | 智能垃圾箱|垃圾房|垃圾分类亭|垃圾分类箱专业生产厂家定做-宿迁市传宇环保设备有限公司 | 半容积式换热器_北京浮动盘管换热器厂家|北京亿丰上达 | 天坛家具官网| 标准光源箱|对色灯箱|色差仪|光泽度仪|涂层测厚仪_HRC大品牌生产厂家 | 大巴租车平台承接包车,通勤班车,巴士租赁业务 - 鸿鸣巴士 | 储气罐,真空罐,缓冲罐,隔膜气压罐厂家批发价格,空压机储气罐规格型号-上海申容压力容器集团有限公司 | 山东商品混凝土搅拌楼-环保型搅拌站-拌合站-分体仓-搅拌机厂家-天宇 | 合肥网带炉_安徽箱式炉_钟罩炉-合肥品炙装备科技有限公司 | led全彩屏-室内|学校|展厅|p3|户外|会议室|圆柱|p2.5LED显示屏-LED显示屏价格-LED互动地砖屏_蕙宇屏科技 | 警方提醒:赣州约炮论坛真的安全吗?2025年新手必看的网络交友防坑指南 | 小青瓦丨古建筑瓦丨青瓦厂家-宜兴市徽派古典建筑材料有限公司 | 一体化预制泵站-一体化提升泵站-一体化泵站厂家-山东康威环保 | 正压送风机-多叶送风口-板式排烟口-德州志诺通风设备 | 高效节能电机_伺服主轴电机_铜转子电机_交流感应伺服电机_图片_型号_江苏智马科技有限公司 | 澳威全屋定制官网|极简衣柜十大品牌|衣柜加盟代理|全屋定制招商 百度爱采购运营研究社社群-店铺托管-爱采购代运营-良言多米网络公司 | 滤芯,过滤器,滤油机,贺德克滤芯,精密滤芯_新乡市宇清流体净化技术有限公司 | 安规_综合测试仪,电器安全性能综合测试仪,低压母线槽安规综合测试仪-青岛合众电子有限公司 | 恒湿机_除湿加湿一体机_恒湿净化消毒一体机厂家-杭州英腾电器有限公司 | loft装修,上海嘉定酒店式公寓装修公司—曼城装饰 | 上海物流公司,上海货运公司,上海物流专线-优骐物流公司 | 招商帮-一站式网络营销服务|互联网整合营销|网络推广代运营|信息流推广|招商帮企业招商好帮手|搜索营销推广|短视视频营销推广 | 智能交通网_智能交通系统_ITS_交通监控_卫星导航_智能交通行业 | 电动高压冲洗车_价格-江苏速利达机车有限公司 | 郑州律师咨询-郑州律师事务所_河南锦盾律师事务所 | 筛分机|振动筛分机|气流筛分机|筛分机厂家-新乡市大汉振动机械有限公司 | led全彩屏-室内|学校|展厅|p3|户外|会议室|圆柱|p2.5LED显示屏-LED显示屏价格-LED互动地砖屏_蕙宇屏科技 | 升降炉_真空气氛炉_管式电阻炉厂家-山东中辰电炉有限公司 | 深圳彩钢板_彩钢瓦_岩棉板_夹芯板_防火复合彩钢板_长鑫 | 气力输送_输送机械_自动化配料系统_负压吸送_制造主力军江苏高达智能装备有限公司! | 青岛侦探调查_青岛侦探事务所_青岛调查事务所_青岛婚外情取证-青岛狄仁杰国际侦探公司 | 盐水蒸发器,水洗盐设备,冷凝结晶切片机,转鼓切片机,絮凝剂加药系统-无锡瑞司恩机械有限公司 | 粘度计NDJ-5S,粘度计NDJ-8S,越平水分测定仪-上海右一仪器有限公司 | 合肥废气治理设备_安徽除尘设备_工业废气处理设备厂家-盈凯环保 合肥防火门窗/隔断_合肥防火卷帘门厂家_安徽耐火窗_良万消防设备有限公司 |