深入理解Java設(shè)計(jì)模式之簡(jiǎn)單工廠模式
一、什么是簡(jiǎn)單工廠模式
簡(jiǎn)單工廠模式又稱為靜態(tài)工廠模式,實(shí)質(zhì)是由一個(gè)工廠類根據(jù)傳入的參數(shù),動(dòng)態(tài)決定應(yīng)該創(chuàng)建哪一個(gè)產(chǎn)品類(這些產(chǎn)品類繼承自一個(gè)父類或接口)的實(shí)例。簡(jiǎn)單工廠模式的創(chuàng)建目標(biāo),所有創(chuàng)建的對(duì)象都是充當(dāng)這個(gè)角色的某個(gè)具體類的實(shí)例。
其實(shí)就是將一個(gè)具體類的實(shí)例化交給一個(gè)靜態(tài)工廠方法來(lái)執(zhí)行,它不屬于GOF的23種設(shè)計(jì)模式,但現(xiàn)實(shí)中卻經(jīng)常會(huì)用到,而且思想也非常簡(jiǎn)單。
二、簡(jiǎn)單工廠模式的結(jié)構(gòu)
簡(jiǎn)單工廠模式包含如下角色:
Factory:工廠角色
Product:抽象產(chǎn)品角色
ConcreteProduct:具體產(chǎn)品角色
| 工廠角色(Creator) | 是簡(jiǎn)單工廠模式的核心,它負(fù)責(zé)實(shí)現(xiàn)創(chuàng)建所有具體產(chǎn)品類的實(shí)例。工廠類可以被外界直接調(diào)用,創(chuàng)建所需的產(chǎn)品對(duì)象。 |
| 抽象產(chǎn)品角色(Product) | 是所有具體產(chǎn)品角色的父類,它負(fù)責(zé)描述所有實(shí)例所共有的公共接口。 |
| 具體產(chǎn)品角色(Concrete Product) | 繼承自抽象產(chǎn)品角色,一般為多個(gè),是簡(jiǎn)單工廠模式的創(chuàng)建目標(biāo)。工廠類返回的都是該角色的某一具體產(chǎn)品。 |
三、簡(jiǎn)單工廠模式的應(yīng)用場(chǎng)景
1.前幾天蘋果公司剛發(fā)布IPhone Xs和iPhone XR,那么問(wèn)題來(lái)了,蘋果公司的代工廠到底生產(chǎn)多少種尺寸的手機(jī)呢?
1.由工廠決定生產(chǎn)哪種型號(hào)的的手機(jī),蘋果公司的工廠就是一個(gè)工廠類,是簡(jiǎn)單工廠模式的核心類。
2.iPhoneX、iPhoneXs、iphoneXr都是蘋果手機(jī),只是型號(hào)不同。蘋果手機(jī)類滿足抽象的定義,各個(gè)型號(hào)的手機(jī)類是其具體實(shí)現(xiàn)。
2.考慮一個(gè)簡(jiǎn)單的軟件應(yīng)用場(chǎng)景,一個(gè)軟件系統(tǒng)可以提供多個(gè)外觀不同的按鈕(如圓形按鈕、矩形按鈕、菱形按鈕等),這些按鈕都源自同一個(gè)基類,不過(guò)在繼承基類后不同的子類修改了部分屬性從而使得它們可以呈現(xiàn)不同的外觀,如果我們希望在使用這些按鈕時(shí),不需要知道這些具體按鈕類的名字,只需要知道表示該按鈕類的一個(gè)參數(shù),并提供一個(gè)調(diào)用方便的方法,把該參數(shù)傳入方法即可返回一個(gè)相應(yīng)的按鈕對(duì)象,此時(shí),就可以使用簡(jiǎn)單工廠模式。
在以下情況下可以使用簡(jiǎn)單工廠模式:
工廠類負(fù)責(zé)創(chuàng)建的對(duì)象比較少:由于創(chuàng)建的對(duì)象較少,不會(huì)造成工廠方法中的業(yè)務(wù)邏輯太過(guò)復(fù)雜。
客戶端只知道傳入工廠類的參數(shù),對(duì)于如何創(chuàng)建對(duì)象不關(guān)心:客戶端既不需要關(guān)心創(chuàng)建細(xì)節(jié),甚至連類名都不需要記住,只需要知道類型所對(duì)應(yīng)的參數(shù)。
四、簡(jiǎn)單工廠模式和工廠方法模式區(qū)別
簡(jiǎn)單工廠模式:
(1)工廠類負(fù)責(zé)創(chuàng)建的對(duì)象比較少,由于創(chuàng)建的對(duì)象較少,不會(huì)造成工廠方法中的業(yè)務(wù)邏輯太過(guò)復(fù)雜。
(2)客戶端只知道傳入工廠類的參數(shù),對(duì)于如何創(chuàng)建對(duì)象并不關(guān)心。
工廠方法模式:
(1)客戶端不知道它所需要的對(duì)象的類。
(2)抽象工廠類通過(guò)其子類來(lái)指定創(chuàng)建哪個(gè)對(duì)象。
五、簡(jiǎn)單工廠模式和策略模式的異同
策略模式和簡(jiǎn)單工廠模式看起來(lái)非常相似,都是通過(guò)多態(tài)來(lái)實(shí)現(xiàn)不同子類的選取,這種思想應(yīng)該是從程序的整體來(lái)看得出的。
如果從使用這兩種模式的角度來(lái)看的話,我們會(huì)發(fā)現(xiàn)在簡(jiǎn)單工廠模式中我們只需要傳遞相應(yīng)的條件就能得到想要的一個(gè)對(duì)象,然后通過(guò)這個(gè)對(duì)象實(shí)現(xiàn)算法的操作。
而策略模式,使用時(shí)必須首先創(chuàng)建一個(gè)想使用的類對(duì)象,然后將該對(duì)象最為參數(shù)傳遞進(jìn)去,通過(guò)該對(duì)象調(diào)用不同的算法。
在簡(jiǎn)單工廠模式中實(shí)現(xiàn)了通過(guò)條件選取一個(gè)類去實(shí)例化對(duì)象,策略模式則將選取相應(yīng)對(duì)象的工作交給模式的使用者,它本身不去做選取工作。
結(jié)合下面的代碼和下面的釋義不難看出,其實(shí)兩個(gè)的差別很微妙,Factory是直接創(chuàng)建具體的對(duì)象并用該對(duì)象去執(zhí)行相應(yīng)的動(dòng)作,而Context將這個(gè)操作給了Context類,沒(méi)有創(chuàng)建具體的對(duì)象,實(shí)現(xiàn)的代碼的進(jìn)一步封裝,客戶端代碼并不需要知道具體的實(shí)現(xiàn)過(guò)程。
六、簡(jiǎn)單工廠模式的優(yōu)缺點(diǎn)
優(yōu)點(diǎn):
工廠類是整個(gè)模式的關(guān)鍵.包含了必要的邏輯判斷,根據(jù)外界給定的信息,決定究竟應(yīng)該創(chuàng)建哪個(gè)具體類的對(duì)象.
通過(guò)使用工廠類,外界可以從直接創(chuàng)建具體產(chǎn)品對(duì)象的尷尬局面擺脫出來(lái),僅僅需要負(fù)責(zé)“消費(fèi)”對(duì)象就可以了。
而不必管這些對(duì)象究竟如何創(chuàng)建及如何組織的.明確了各自的職責(zé)和權(quán)利,有利于整個(gè)軟件體系結(jié)構(gòu)的優(yōu)化。
缺點(diǎn):
由于工廠類集中了所有實(shí)例的創(chuàng)建邏輯,違反了開(kāi)閉原則,將全部創(chuàng)建邏輯集中到了一個(gè)工廠類中;
它所能創(chuàng)建的類只能是事先考慮到的,如果需要添加新的類,則就需要改變工廠類了。
當(dāng)系統(tǒng)中的具體產(chǎn)品類不斷增多時(shí)候,可能會(huì)出現(xiàn)要求工廠類根據(jù)不同條件創(chuàng)建不同實(shí)例的需求.
這種對(duì)條件的判斷和對(duì)具體產(chǎn)品類型的判斷交錯(cuò)在一起,很難避免模塊功能的蔓延,對(duì)系統(tǒng)的維護(hù)和擴(kuò)展非常不利;
開(kāi)閉原則定義:一個(gè)軟件實(shí)體如類、模塊和函數(shù)應(yīng)該對(duì)擴(kuò)展開(kāi)放,對(duì)修改關(guān)閉。
開(kāi)放-封閉原則的意思就是說(shuō),你設(shè)計(jì)的時(shí)候,時(shí)刻要考慮,盡量讓這個(gè)類是足夠好,寫(xiě)好了就不要去修改了,如果新需求來(lái),我們?cè)黾右恍╊惥屯晔铝耍瓉?lái)的代碼能不動(dòng)則不動(dòng)。這個(gè)原則有兩個(gè)特性,一個(gè)是說(shuō)“對(duì)于擴(kuò)展是開(kāi)放的”,另一個(gè)是說(shuō)“對(duì)于更改是封閉的”。面對(duì)需求,對(duì)程序的改動(dòng)是通過(guò)增加新代碼進(jìn)行的,而不是更改現(xiàn)有的代碼。這就是“開(kāi)放-封閉原則”的精神所在。
七、簡(jiǎn)單工廠模式的實(shí)現(xiàn)
首先創(chuàng)建一個(gè)"蘋果手機(jī)"類,定義一個(gè)獲取手機(jī)尺寸的方法
//蘋果手機(jī)
public abstract class ApplePhone {
//獲取尺寸
protected abstract void getSize();
}
蘋果手機(jī)不同型號(hào)的"手機(jī)類"。
public class IphoneX:ApplePhone{
public void getSize() {
Console.WriteLine("iPhoneX屏幕:3.5英寸");
}
}
public class IphoneXs:ApplePhone{
public void getSize() {
Console.WriteLine("iPhoneX屏幕:4.5英寸");
}
}
public class IphoneXR:ApplePhone{
public void getSize() {
Console.WriteLine("iPhoneX屏幕:5.5英寸");
}
}
建立一個(gè)"工廠類"生產(chǎn)不同型號(hào)的"手機(jī)對(duì)象"。
//蘋果工廠
public class AppleFactory {
public static ApplePhone createPhone(String model){
ApplePhone applePhone = null;
switch (model) {
case"iPhoneX":
applePhone = new IphoneX();
break;
case"iPhoneXs":
applePhone = new IphoneXs();
break;
case"iPhoneXr":
applePhone = new IphoneXR();
break;
default:
break;
}
returnapplePhone;
}
}
最后是客戶端測(cè)試類
public class Client {
public static void main(String[] args) {
ApplePhone applePhone ;
applePhone = AppleFactory.createPhone("iPhoneX");
applePhone.getSize();
applePhone = AppleFactory.createPhone("iPhoneXs");
applePhone.getSize();
applePhone = AppleFactory.createPhone("iPhoneXr");
applePhone.getSize();
}
}
八、總結(jié)
創(chuàng)建型模式對(duì)類的實(shí)例化過(guò)程進(jìn)行了抽象,能夠?qū)?duì)象的創(chuàng)建與對(duì)象的使用過(guò)程分離。
簡(jiǎn)單工廠模式又稱為靜態(tài)工廠方法模式,它屬于類創(chuàng)建型模式。在簡(jiǎn)單工廠模式中,可以根據(jù)參數(shù)的不同返回不同類的實(shí)例。
簡(jiǎn)單工廠模式專門定義一個(gè)類來(lái)負(fù)責(zé)創(chuàng)建其他類的實(shí)例,被創(chuàng)建的實(shí)例通常都具有共同的父類。
簡(jiǎn)單工廠模式包含三個(gè)角色:工廠角色負(fù)責(zé)實(shí)現(xiàn)創(chuàng)建所有實(shí)例的內(nèi)部邏輯;抽象產(chǎn)品角色是所創(chuàng)建的所有對(duì)象的父類,負(fù)責(zé)描述所有實(shí)例所共有的公共接口;具體產(chǎn)品角色是創(chuàng)建目標(biāo),所有創(chuàng)建的對(duì)象都充當(dāng)這個(gè)角色的某個(gè)具體類的實(shí)例。
簡(jiǎn)單工廠模式的要點(diǎn)在于:當(dāng)你需要什么,只需要傳入一個(gè)正確的參數(shù),就可以獲取你所需要的對(duì)象,而無(wú)須知道其創(chuàng)建細(xì)節(jié)。
簡(jiǎn)單工廠模式最大的優(yōu)點(diǎn)在于實(shí)現(xiàn)對(duì)象的創(chuàng)建和對(duì)象的使用分離,將對(duì)象的創(chuàng)建交給專門的工廠類負(fù)責(zé),但是其最大的缺點(diǎn)在于工廠類不夠靈活,增加新的具體產(chǎn)品需要修改工廠類的判斷邏輯代碼,而且產(chǎn)品較多時(shí),工廠方法代碼將會(huì)非常復(fù)雜。
簡(jiǎn)單工廠模式適用情況包括:工廠類負(fù)責(zé)創(chuàng)建的對(duì)象比較少;客戶端只知道傳入工廠類的參數(shù),對(duì)于如何創(chuàng)建對(duì)象不關(guān)心。
本篇文章就到這里了,希望能夠給你帶來(lái)幫助,也希望您能夠多多關(guān)注腳本之家的更多內(nèi)容!
相關(guān)文章
SpringBoot詳細(xì)講解如何創(chuàng)建及刷新Spring容器bean
前面看spring源碼時(shí)可以發(fā)現(xiàn)refresh()方法十分重要。在這個(gè)方法中會(huì)加載beanDefinition,同時(shí)創(chuàng)建bean對(duì)象。那么在springboot中有沒(méi)有使用這個(gè)refresh()方法呢2022-06-06
Spring boot整合Springfox生成restful的在線api文檔
這篇文章主要為大家介紹了Spring boot整合Springfox生成restful在線api文檔,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步2022-03-03
J2EE Servlet上傳文件到服務(wù)器并相應(yīng)顯示功能的實(shí)現(xiàn)代碼
這篇文章主要介紹了J2EE Servlet上傳文件到服務(wù)器,并相應(yīng)顯示,在文中上傳方式使用的是post不能使用get,具體實(shí)例代碼大家參考下本文2018-07-07
SpringCloud的JPA連接PostgreSql的教程
這篇文章主要介紹了SpringCloud的JPA接入PostgreSql 教程,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-06-06
spring mvc+localResizeIMG實(shí)現(xiàn)HTML5端圖片壓縮上傳
這篇文章主要為大家詳細(xì)介紹了使用spring mvc+localResizeIMG實(shí)現(xiàn)HTML5端圖片壓縮上傳,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-04-04
擴(kuò)展tk.mybatis的流式查詢功能實(shí)現(xiàn)
mybatis查詢默認(rèn)是一次獲取全部,如果數(shù)據(jù)過(guò)于龐大,就會(huì)導(dǎo)致OOM問(wèn)題,本文就介紹了tk.mybatis 流式查詢,具有一定的參考價(jià)值,感興趣的可以了解一下2021-12-12

