java23種設(shè)計(jì)模式——三、工廠模式

源碼在我的githubgitee中獲取

工廠模式

工廠模式介紹

    工廠模式是我們最常用的實(shí)例化對(duì)象模式了烹看,是用工廠方法代替new操作的一種模式国拇。著名的Jive論壇 ,就大量使用了工廠模式,工廠模式在Java程序系統(tǒng)可以說是隨處可見惯殊。因?yàn)楣S模式就相當(dāng)于創(chuàng)建實(shí)例對(duì)象的new酱吝,我們經(jīng)常要根據(jù)類Class生成實(shí)例對(duì)象,如A a=new A() 工廠模式也是用來創(chuàng)建實(shí)例對(duì)象的土思,所以以后new時(shí)就要多個(gè)心眼务热,是否可以考慮使用工廠模式,雖然這樣做己儒,可能多做一些工作崎岂,但會(huì)給你系統(tǒng)帶來更大的可擴(kuò)展性和盡量少的修改量。(百度百科)

    工廠模式又分為:
  • 簡(jiǎn)單工廠模式:允許接口創(chuàng)建對(duì)象闪湾,但不會(huì)暴露對(duì)象的創(chuàng)建邏輯冲甘。
  • 工廠方法模式: 允許接口創(chuàng)建對(duì)象,但使用哪個(gè)類來創(chuàng)建對(duì)象途样,則是交由子類決定的
  • 抽象方法模式: 抽象工廠是一個(gè)能夠創(chuàng)建一系列相關(guān)的對(duì)象而無需指定/公開其具體類的接口江醇。該模式能夠提供其他工廠的對(duì)象,在其內(nèi)部創(chuàng)建其他對(duì)象何暇。

簡(jiǎn)單工廠模式

屬于創(chuàng)建型模式陶夜,又叫做靜態(tài)工廠方法模式,不屬于23種GOF設(shè)計(jì)模式之一赖晶。是由一個(gè)工廠對(duì)象決定創(chuàng)建出哪一種產(chǎn)品類的實(shí)例律适。違背“開放 - 關(guān)閉原則”,一旦添加新產(chǎn)品就不得不修改工廠類的邏輯遏插,這樣就會(huì)造成工廠邏輯過于復(fù)雜捂贿。

假設(shè)現(xiàn)在有一家餐館

public interface Restaurant {
   public void cook();
}

餐館有兩種菜品:紅燒肉和雞蛋羹

//雞蛋羹
public class Egg implements Restaurant {
    @Override
    public void cook() {
        System.out.println("雞蛋羹做好了");
    }
}
//紅燒肉
public class Meet implements Restaurant{
    @Override
    public void cook() {
        System.out.println("紅燒肉做好了");
    }
}

餐館里有服務(wù)員,來負(fù)責(zé)向后廚傳達(dá)客人的需求

public class Waiter {
    //同樣可以定義常量然后通過switch語句來實(shí)現(xiàn)
    public static Restaurant getFood(String orderType) {
        Restaurant restaurant = null;
        if(orderType.equals("紅燒肉")){
            restaurant = new Meet();
        }else if (orderType.equals("雞蛋羹")){
            restaurant = new Egg();
        }
        return restaurant;
    }
}

現(xiàn)在顧客來了胳嘲,要點(diǎn)一份紅燒肉厂僧,就只需要和服務(wù)員說就行

public class Customer {
    public static void main(String[] args) {
        Restaurant restaurant = Waiter.getFood("紅燒肉");
        restaurant.cook();
    }
}

輸出

紅燒肉做好了

通過以上方法,的確實(shí)現(xiàn)了 提供創(chuàng)建實(shí)例的功能了牛,而無需關(guān)心具體實(shí)現(xiàn)颜屠。但是我們不難發(fā)現(xiàn),這種方法的擴(kuò)展性很差鹰祸,如果餐館新出了一款菜品甫窟,還需要我們?cè)诜?wù)員方法里修改。這使得當(dāng)餐館的菜品很多時(shí)蛙婴,工廠方法代碼邏輯將會(huì)非常復(fù)雜

工廠方法模式

工廠方法模式粗井,又稱工廠模式、多態(tài)工廠模式和虛擬構(gòu)造器模式街图,通過定義工廠父類負(fù)責(zé)定義創(chuàng)建對(duì)象的公共接口浇衬,而子類則負(fù)責(zé)生成具體的對(duì)象。是在工廠模式家族中是用的最多模式餐济,一般項(xiàng)目中存在最多的就是這個(gè)模式耘擂。是對(duì)簡(jiǎn)單工廠模式的一個(gè)優(yōu)化,讓每個(gè)對(duì)象都有一個(gè)與之對(duì)應(yīng)的工廠絮姆。

這里我們接著用上面的例子醉冤,假設(shè)這家餐廳的生意非常好,所以餐館的老板把餐館所有負(fù)責(zé)點(diǎn)餐的服務(wù)員都辭退了滚朵,取而代之的是添加了一個(gè)收銀臺(tái)冤灾,然后讓每個(gè)廚師只負(fù)責(zé)做一樣菜。這樣客人只需要和收銀臺(tái)說要求就行了辕近。

這里我們接著用上面的類韵吨。除去服務(wù)員Waiter類

新建Cashier接口

/**
 * @author codermy
 * @createTime 2020/6/15
 */
public interface Cashier {
    public Restaurant getFood();
}

然后給每一個(gè)菜品新建一個(gè)工廠類

EggCooker

/**
 * @author codermy
 * @createTime 2020/6/15
 */
public class EggCooker implements Cashier {
    @Override
    public Restaurant getFood() {
        return new Egg();
    }
}

MeetCooker

/**
 * @author codermy
 * @createTime 2020/6/15
 */
public class MeetCooker implements Cashier{
    @Override
    public Restaurant getFood() {
        return new Meet();
    }
}

然后顧客點(diǎn)單只需要在收銀臺(tái),餐廳的系統(tǒng)會(huì)自動(dòng)將信息傳遞給相應(yīng)的廚師移宅,對(duì)應(yīng)的廚師就能在餐館中把菜做好

/**
 * @author codermy
 * @createTime 2020/6/15
 * 消費(fèi)者
 */
public class Customer {
    public static void main(String[] args) {
        Cashier order = new EggCooker();
        Restaurant food = order.getFood();
        food.cook();
    }
}

輸出結(jié)果

雞蛋羹做好了

工廠方法模式解決了簡(jiǎn)單工廠模式不符合的開閉原則归粉,當(dāng)添加一個(gè)菜品時(shí),只需要再雇傭一個(gè)廚師就行(從現(xiàn)實(shí)角度看漏峰,老板有點(diǎn)虧哦)糠悼。但是這也增加了系統(tǒng)的復(fù)雜度(菜越多,廚師就越多浅乔,這哪家餐館頂?shù)淖倔喂。?/p>

抽象工廠模式

這個(gè)模式解決了每個(gè)工廠只能創(chuàng)建一類產(chǎn)品(工廠方法模式)的問題

這里用餐館的例子不太形象铝条,不是很容易理解,強(qiáng)行舉例可能會(huì)和上面的方法弄混席噩,我自己繞了好一會(huì)班缰,所以我們換一個(gè)例子。

現(xiàn)在我們?nèi)耸植浑x手機(jī)悼枢,我們假設(shè)手機(jī)有如下幾個(gè)功能

//手機(jī)產(chǎn)品接口
public interface IphoneProduct {
    void callup();//打電話
    void sendSms();//發(fā)短信
}

每個(gè)人家里又都有路由器埠忘,路由器有如下功能

//路由器產(chǎn)品接口
public interface IRouterProduct {
    void openwifi();//開啟wifi
    void setting();//設(shè)置wifi
}

然后現(xiàn)在有一個(gè)抽象產(chǎn)品工廠,是來生產(chǎn)這兩樣產(chǎn)品的馒索,假設(shè)生產(chǎn)手機(jī)和路由器的方法是一樣的莹妒,只是需要加上廠商信息

//抽象產(chǎn)品工廠
public interface IProductFactory {
    //生產(chǎn)手機(jī)
    IphoneProduct iphoneProduct();
    //生產(chǎn)路由器
    IRouterProduct iRouterProduct();
}

現(xiàn)在有兩家廠商,小米和華為工廠绰上,可以生產(chǎn)手機(jī)和路由器旨怠,他們兩家廠商分別由兩條產(chǎn)業(yè)線來做手機(jī)和路由器

//小米手機(jī)
public class XiaomiPhone implements IphoneProduct{

    @Override
    public void callup() {
        System.out.println("用小米手機(jī)打電話");
    }

    @Override
    public void sendSms() {
        System.out.println("用小米手機(jī)發(fā)短信");
    }
}

//小米路由器
public class XiaomiRouter implements IRouterProduct {

    @Override
    public void openwifi() {
        System.out.println("打開小米wifi");
    }

    @Override
    public void setting() {
        System.out.println("設(shè)置小米wifi");
    }
}

//小米廠商
public class XiaomiFactory implements IProductFactory {
    @Override
    public IphoneProduct iphoneProduct() {
        return new XiaomiPhone();
    }

    @Override
    public IRouterProduct iRouterProduct() {
        return new XiaomiRouter();
    }
}

//華為手機(jī)
public class HuaweiPhone implements IphoneProduct {

    @Override
    public void callup() {
        System.out.println("用華為手機(jī)打電話");
    }

    @Override
    public void sendSms() {
        System.out.println("用華為手機(jī)發(fā)短信");
    }
}
//華為路由器
    public class HuaweiRouter implements IRouterProduct {

        @Override
        public void openwifi() {
            System.out.println("打開華為wifi");
        }

        @Override
        public void setting() {
            System.out.println("設(shè)置華為wifi");
        }
    }
//華為工廠
public class HuaweiFactory implements IProductFactory {
    @Override
    public IphoneProduct iphoneProduct() {
        return new HuaweiPhone();
    }

    @Override
    public IRouterProduct iRouterProduct() {
        return new HuaweiRouter();
    }
}

消費(fèi)者類

//消費(fèi)者/測(cè)試類
public class Customer {
    public static void main(String[] args) {

        System.out.println("==============小米產(chǎn)品=================");
        XiaomiFactory xiaomiFactory = new XiaomiFactory();//新建一個(gè)小米工廠
        IphoneProduct xiaomiiphoneProduct = xiaomiFactory.iphoneProduct();//小米工廠開始生產(chǎn)小米手機(jī)
        xiaomiiphoneProduct.callup();//測(cè)試小米手機(jī)打電話功能
        IRouterProduct xiaomiiRouterProduct = xiaomiFactory.iRouterProduct();//小米工廠開始生產(chǎn)小米路由器
        xiaomiiRouterProduct.openwifi();//測(cè)試小米路由器打開wifi功能

        System.out.println("==============華為產(chǎn)品=================");
        HuaweiFactory huaweiFactory = new HuaweiFactory();

        IphoneProduct huaweiiphoneProduct1 = huaweiFactory.iphoneProduct();
        huaweiiphoneProduct1.callup();
        IRouterProduct huaweiiRouterProduct = huaweiFactory.iRouterProduct();
        huaweiiRouterProduct.openwifi();
    }
}

輸出

==============小米產(chǎn)品=================
用小米手機(jī)打電話
打開小米wifi
==============華為產(chǎn)品=================
用華為手機(jī)打電話
打開華為wifi

抽象工廠模式相較于以上兩種模式難以理解一些。這里提供另一種寫法比較好理解蜈块,來自Guide哥的博客(以下所有內(nèi)容)

不知道大家玩過穿越火線或者吃雞這類游戲了嗎运吓,游戲中存在各種槍。我們假設(shè)現(xiàn)在存在AK疯趟、M4A1兩類槍拘哨,每一種槍對(duì)應(yīng)一種子彈。我們現(xiàn)在這樣考慮生產(chǎn)AK的工廠可以順便生產(chǎn)AK使用的子彈信峻,生產(chǎn)M4A1的工廠可以順便生產(chǎn)M4A1使用的子彈倦青。(AK工廠生產(chǎn)AK系列產(chǎn)品包括子彈啊,AK槍的類型啊這些盹舞,M4A1工廠同理)
————————————————

(1)創(chuàng)建相關(guān)接口:

public interface Gun {
    public void shooting();
}

子彈

public interface Bullet {
    public void load();
}

(2)創(chuàng)建接口對(duì)應(yīng)實(shí)現(xiàn)類:

AK類

public class AK implements Gun{

    @Override
    public void shooting() {
        System.out.println("shooting with AK");

    }

}

M4A1類

public class M4A1 implements Gun {

    @Override
    public void shooting() {
        System.out.println("shooting with M4A1");

    }

}

AK子彈類

public class AK_Bullet implements Bullet {

    @Override
    public void load() {
        System.out.println("Load bullets with AK");
    }

}

M4A1子彈類

public class M4A1_Bullet implements Bullet {

    @Override
    public void load() {
        System.out.println("Load bullets with M4A1");
    }

}

(3)創(chuàng)建工廠接口

public interface Factory {
    public Gun produceGun();
    public Bullet produceBullet();
}


(4)創(chuàng)建具體工廠

生產(chǎn)AK和AK子彈的工廠

public class AK_Factory implements Factory{

    @Override
    public Gun produceGun() {
        return new AK();
    }

    @Override
    public Bullet produceBullet() {
        return new AK_Bullet();
    }

}


生產(chǎn)M4A1和M4A1子彈的工廠

public class M4A1_Factory implements Factory{

    @Override
    public Gun produceGun() {
        return new M4A1();
    }

    @Override
    public Bullet produceBullet() {
        return new M4A1_Bullet();
    }

}


(5)測(cè)試

public class Test {

    public static void main(String[] args) {  

     Factory factory;
     Gun gun;
     Bullet bullet;

     factory =new AK_Factory();
     bullet=factory.produceBullet();
     bullet.load();
     gun=factory.produceGun();
     gun.shooting(); 

    }

}

輸出結(jié)果:

Load bullets with AK
shooting with AK
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末产镐,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子踢步,更是在濱河造成了極大的恐慌癣亚,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,509評(píng)論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件获印,死亡現(xiàn)場(chǎng)離奇詭異述雾,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)兼丰,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,806評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門玻孟,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人鳍征,你說我怎么就攤上這事黍翎。” “怎么了艳丛?”我有些...
    開封第一講書人閱讀 163,875評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵匣掸,是天一觀的道長(zhǎng)趟紊。 經(jīng)常有香客問我,道長(zhǎng)碰酝,這世上最難降的妖魔是什么织阳? 我笑而不...
    開封第一講書人閱讀 58,441評(píng)論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮砰粹,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘造挽。我一直安慰自己碱璃,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,488評(píng)論 6 392
  • 文/花漫 我一把揭開白布饭入。 她就那樣靜靜地躺著嵌器,像睡著了一般。 火紅的嫁衣襯著肌膚如雪谐丢。 梳的紋絲不亂的頭發(fā)上爽航,一...
    開封第一講書人閱讀 51,365評(píng)論 1 302
  • 那天,我揣著相機(jī)與錄音乾忱,去河邊找鬼讥珍。 笑死,一個(gè)胖子當(dāng)著我的面吹牛窄瘟,可吹牛的內(nèi)容都是我干的衷佃。 我是一名探鬼主播,決...
    沈念sama閱讀 40,190評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼蹄葱,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼氏义!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起图云,我...
    開封第一講書人閱讀 39,062評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤惯悠,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后竣况,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體克婶,經(jīng)...
    沈念sama閱讀 45,500評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,706評(píng)論 3 335
  • 正文 我和宋清朗相戀三年丹泉,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了鸠补。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,834評(píng)論 1 347
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡嘀掸,死狀恐怖紫岩,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情睬塌,我是刑警寧澤泉蝌,帶...
    沈念sama閱讀 35,559評(píng)論 5 345
  • 正文 年R本政府宣布悯辙,位于F島的核電站缰儿,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜挥吵,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,167評(píng)論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望李破。 院中可真熱鬧拴测,春花似錦、人聲如沸违孝。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,779評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽雌桑。三九已至喇喉,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間校坑,已是汗流浹背拣技。 一陣腳步聲響...
    開封第一講書人閱讀 32,912評(píng)論 1 269
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留耍目,地道東北人膏斤。 一個(gè)月前我還...
    沈念sama閱讀 47,958評(píng)論 2 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像邪驮,于是被迫代替她去往敵國(guó)和親掸绞。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,779評(píng)論 2 354