Java 大白話講解設計模式之 -- 工廠模式

聲明:原創文章,轉載請註明出處https://www.jianshu.com/p/201d0d0fb7e6

李華是一位在軟件公司工作的程序員,每天敲着代碼,從早到晚,日復一日。某天晚上,李華躺在牀上遲遲未睡着:難道這就是我要的生活嗎?不甘平庸的李華,決定找點其他事情做做了。但是除了敲代碼,我還能幹嘛呢?李華在敲代碼之餘,平時還有個收集杯子的愛好,於是就決定開一個杯子店。

一開始他決定先賣陶瓷杯子,因爲製作工業相對簡單,網上也有很多教程,聰明又好學的李華很快就掌握了製作陶瓷杯子的工藝。很快他的杯子店鋪也開張了!李華是一位佛系店主,顧客來買一個杯子,他就給人現做一個,剛開始店裏人流不多,李華還能應付的過來,慢慢的隨着李華的製作工業越來越成熟,杯子質量也越來越好,前來購買的顧客漸漸多了起來,每來一個顧客,李華都得重新制作一個杯子,效率極低。這讓李華很困惑,這樣搞下去連褲頭都要虧掉了。。。而且隨着店鋪名氣的增大,有很多顧客提出了想購買其他杯子的需求,比如玻璃杯,李華眼看這麼好的流量也不能拒絕吧。於是李華決定他要改變下他的商業模式,從自產自銷到工廠代銷。即李華找了一家杯子的工廠,顧客想要什麼杯子,直接去這家工廠進貨。就這樣李華的杯子店鋪又有條不紊的營業着。

晚上回家,李華不由的覺得這個工廠代銷的商業模式很好,於是決定做個總結記錄,程序員出生的李華當然離不開他的老毛病,喜歡用代碼來說明問題。。。接下來我們就一起來看下他是如何總結的。
首先不管是陶瓷杯還是玻璃杯,他都是杯子,於是先創建了一個杯子接口:

public interface Cup {
    void useCup();
}

然後是陶瓷杯子和玻璃杯子分別實現這個接口:
陶瓷杯子:

public class CeramicsCup implements Cup {
    @Override
    public void useCup() {
        System.out.println("我正在使用陶瓷杯子。。。");
    }
}

玻璃杯子:

public class GlassCup implements Cup {
    @Override
    public void useCup() {
        System.out.println("我正在使用玻璃杯子。。。");
    }
}

然後是杯子工廠:

public class CupFactory {
    public Cup productCup(String cupType) {
        switch (cupType) {
            case "ceramics":
                return new CeramicsCup();
            case "glass":
                return new GlassCup();
            default:
                return new CeramicsCup();
        }
    }
}

這個杯子工廠需要傳入你要的杯子類型就會爲你生產出你想要的杯子。
然後看下李華的店鋪,首先看下之前自產自銷的模式:

public class Client {
    public static void main(String[] arg){
        CeramicsCup ceramicsCup = new CeramicsCup();
        ceramicsCup.useCup();
        GlassCup glassCup = new GlassCup();
        glassCup.useCup();
    }
}
------------------------------
運行結果:
我正在使用陶瓷杯子。。。
我正在使用玻璃杯子。。。
------------------------------

再來看下使用工廠的模式:

public class Client {
    public static void main(String[] arg){
        Cup ceramicsCup = CupFactory.productCup("ceramics");
        ceramicsCup.useCup();
        Cup cup = CupFactory.productCup("glass");
        cup.useCup();
    }
}
------------------------------
運行結果:
我正在使用陶瓷杯子。。。
我正在使用玻璃杯子。。。
------------------------------

可以看到,李華直接從工廠進貨後,效率有了很大的提升,因爲之前每次當顧客要買杯子的時候,都得自己從頭到尾製作一個,而且有的時候還會在製作的時候由於誤操作,製作出劣質的杯子,可謂漏洞百出。而用工廠進貨的模式後,李華就不用把心思花在杯子的製作上去,可以把精力花在店鋪的整體運營上去,只要顧客有杯子的需要,直接去工廠進貨就可以了,而且工廠有專業成熟的製作工藝,質量也有保障,從而他的店鋪經營的也就越穩定。
李華寫完總結後,不禁感嘆,這不就是設計模式中的簡單工廠模式嗎(黑人問號臉)

什麼是簡單工廠模式:
定義:定義一個工廠類,根據傳入的參數不同返回不同的實例,被創建的實例具有共同的父類或接口。

其實嚴格來說簡單工廠並不算是一種設計模式,而是大家的一種編程習慣。
李華寫完總結後,內心毫無波瀾,甚至還有點想畫下這個模式的UML類圖。。。

李華畫完UML類圖後,不禁感嘆,編程真是不處不在啊。
第二天,李華的店裏突然跑來一個顧客,說是要買1000個塑料杯,可李華的店鋪並沒有塑料杯賣,於是他便打電話給杯子工廠,不幸的是杯子工廠也沒有生產塑料杯的。這可讓李華愁壞了,眼看這個大訂單也不好拒絕。於是李華親自跑到了工廠,找到了老闆,希望能夠說服老闆生產他的塑料杯。可想而知,這肯定被老闆拒絕了,因爲工廠生產不同的杯子,他的製作流程,工藝等都是不一樣的,每增加一種類型,工廠就得引進生產該類型的設備,相應的成本也會增加。不過李華,還是沒有放棄,一直和老闆軟磨硬泡,並且老闆看李華的店鋪生意也不錯,於是就答應下來了,特意爲此新增了一條製作塑料杯的生產線,這樣這個工廠就有三條生產線了:

public class CupFactory {
   public static Cup productCup(String cupType) {
       switch (cupType) {
           case "ceramics":
               return new CeramicsCup();
           case "glass":
               return new GlassCup();
           case "plastic":
               return new PlasticCup();
           default:
               return new CeramicsCup();
       }
   }
}

很快工廠的1000個塑料杯子就交付了,李華因此大賺了一筆,店鋪的生意也越來越好。
一段時間後,店裏又突然來了一位顧客,小聲地問李華:你們這。。有沒有。。擼擼杯!,很急!李華聽後又是一個黑人問號臉,還有這種操作???李華很想幫忙,但無奈店裏沒有賣,就禮貌的拒絕了。隨着李華的店鋪名氣越來越大,來店裏問擼擼杯的顧客還真不少。李華覺得這又是一個機會,反正都是杯子,賣什麼不是賣。。。(是的李華是一個沒有節操的奸商)於是李華又跑去工廠找老闆了。。老闆一聽WTF,你把我這當什麼了,不是什麼都能生產的。李華和老闆吵了一架便被轟了出來。
李華很鬱悶,晚上躺在牀上,細想了下,其實這種模式還是有點問題的。因爲把所有杯子的生產都交給了一個工廠。這樣就會導致這個工廠很不靈活,每次想增加生產一種杯子,工廠就得變動,引入新的設備、製作工藝等,這樣這個工廠就會非常不穩定。聰明的李華,很快有了新想法,爲什麼要依賴一個工廠,我就不能多找幾個工廠,每個工廠只負責生產一種杯子。這樣就沒有上面的問題。而且非常靈活,需要什麼杯子只用到什麼工廠進貨就可以了。店裏銷售的杯子種類也不會有限制,顧客要是想買新類型的杯子,只用再聯繫一家生產這種類型杯子的工廠就可以了。說幹就幹,正好趁着這次和原來工廠老闆鬧翻,李華決定棄用這個工廠,並且重新找了四家新工廠,分別生產陶瓷杯、玻璃杯、塑料杯還有擼擼杯。。。就這樣,李華的店鋪又引來了新的流量高峯。
晚上回到家,李華又開始總結他的新模式:
首先李華新聯繫的工廠都有一個共同的屬性就是都是生產杯子的,那麼就可以定義一個工廠接口,只生產杯子:

public interface Factory {
    Cup productCup();
}

然後分別是4個不同類型的杯子工廠實現這個接口:

陶瓷杯工廠:

public class CeramicsCupFactory implements Factory {
    @Override
    public Cup productCup() {
        return new CeramicsCup();
    }
}

玻璃杯工廠:

public class GlassCupFactory implements Factory {
    @Override
    public Cup productCup() {
        return new GlassCup();
    }
}

塑料杯工廠:

public class PlasticCupFactory implements Factory {
    @Override
    public Cup productCup() {
        return new PlasticCup();
    }
}

擼擼杯工廠:

public class PlaneCupFactory implements Factory {
    @Override
    public Cup productCup() {
        return new PlaneCup();
    }
}

接着在來看下李華的店鋪:

public class Client {
    public static void main(String[] arg){
        CeramicsCupFactory ceramicsCupFactory = new CeramicsCupFactory();
        Cup ceramicsCup = ceramicsCupFactory.productCup();
        ceramicsCup.useCup();
        GlassCupFactory glassCupFactory = new GlassCupFactory();
        Cup glassCup = glassCupFactory.productCup();
        glassCup.useCup();
        PlaneCupFactory planeCupFactory = new PlaneCupFactory();
        Cup planeCup = planeCupFactory.productCup();
        planeCup.useCup();
    }
}
------------------------------
運行結果:
我正在使用陶瓷杯子。。。
我正在使用玻璃杯子。。。
我正在使用擼擼杯。。。
------------------------------

可以看到,當顧客想要某種杯子的時候,李華就直接聯繫生產該類型杯子的工廠,當然這裏的工廠實例可以設置成單例,畢竟工廠建好了,就好了,不用反覆創建,哪天需要杯子的時候直接提貨就可以了。當然這種模式在設計模式中也是有原型的,就是工廠方法模式

工廠方法模式:
定義一個用於創建對象的接口,讓子類決定將哪一個類實例化。工廠方法模式讓一個類的實例化延遲到其子類。

工廠方法模式和之前的簡單工廠方法相比優勢還是很明顯的,變得更加靈活,擴展性也更好。在簡單工廠方法中,要想新增類型,就只能修改原有工廠代碼,我們知道設計模式中一條重要的原則就是對修改關閉,對擴展開放,通俗點就是,可以新增代碼,但是儘量少修改原有代碼,因爲一修改,就會給程序帶來不穩定性等問題。

最後愛總結的李華還不忘畫了下這個工廠方法模式的UML類圖:


就這樣,李華的杯子店越來越像是這麼回事了,經營的越來越好。不過漸漸的李華總覺得,賣的杯子少了點東西,不夠完美。原來之前李華爲了節約成本,生產的杯子都是沒有帶蓋子的,現在李華的店生意越來越好,爲了能夠更人性化,就想着免費爲每個生產出的杯子帶上一個蓋子。於是就依次聯繫了之前的四家工廠,希望每個工廠生產出的杯子都帶一個蓋子,當然工廠老闆是不太願意的,因爲增加蓋子的話,又得引入一套蓋子的生產線。不過鑑於和李華合作這麼久,而且李華的店鋪生意也很好,於是就答應了。這樣李華之前總結的模式變成了如下:
首先因爲新增不同類型的杯蓋,所以需要一個蓋子接口:

public interface Cover {
     //杯蓋有保持杯子清潔的功能
    void clean();
}

然後分別是具體的杯蓋:
陶瓷杯蓋:

public class CeramicsCover implements Cover {
    @Override
    public void clean() {
        System.out.println("我是一隻陶瓷杯蓋");
    }
}

玻璃杯蓋:

public class GlassCover implements Cover {
    @Override
    public void clean() {
        System.out.println("我是一隻玻璃杯蓋");
    }
}

擼擼杯蓋:

public class PlaneCover implements Cover {
    @Override
    public void clean() {
        System.out.println("我是一隻擼擼杯蓋");
    }
}

然後得修改生產杯子的工廠,修改的地方有兩處,第一就是工廠的共同的接口,另外就是具體的工廠。
工廠接口:

public interface Factory {
    Cup productCup();
    //新增杯蓋生產
    Cover productCover();
}

然後是具體工廠需要新增對應的杯蓋生產線:
陶瓷工廠:

public class CeramicsCupFactory implements Factory {
    @Override
    public Cup productCup() {
        return new CeramicsCup();
    }

    @Override
    public Cover productCover() {
        return new CeramicsCover();
    }
}

玻璃工廠:

public class GlassCupFactory implements Factory {
    @Override
    public Cup productCup() {
        return new GlassCup();
    }

    @Override
    public Cover productCover() {
        return new GlassCover();
    }
}

擼擼杯工廠:

public class PlaneCupFactory implements Factory {
    @Override
    public Cup productCup() {
        return new PlaneCup();
    }

    @Override
    public Cover productCover() {
        return new PlaneCover();
    }
}

然後看下店鋪:

public class Client {
    public static void main(String[] arg){
        CeramicsCupFactory ceramicsCupFactory = new CeramicsCupFactory();
        Cup ceramicsCup = ceramicsCupFactory.productCup();
        Cover ceramicsCover = ceramicsCupFactory.productCover();
        ceramicsCup.useCup();
        ceramicsCover.clean();
        GlassCupFactory glassCupFactory = new GlassCupFactory();
        Cup glassCup = glassCupFactory.productCup();
        Cover glassCover = glassCupFactory.productCover();
        glassCup.useCup();
        glassCover.clean();
        PlaneCupFactory planeCupFactory = new PlaneCupFactory();
        Cup planeCup = planeCupFactory.productCup();
        Cover planeCover= planeCupFactory.productCover();
        planeCup.useCup();
        planeCover.clean();
    }
}
------------------------------
運行結果:
我正在使用陶瓷杯子。。。
我是一隻陶瓷杯蓋
我正在使用玻璃杯子。。。
我是一隻玻璃杯蓋
我正在使用擼擼杯。。。
我是一隻擼擼杯蓋
------------------------------

可以看到這個模式與之前的工廠方法模式有所不同,每個工廠不只生產一種商品,而是生產一個系列,或者說是一套的東西。我們稱之爲抽象工廠模式

抽象工廠模式:
提供一個創建一系列相關或相互依賴對象的接口,而無須指定它們具體的類。( 在抽象工廠模式中,每一個具體工廠都提供了多個工廠方法用於產生多種不同類型的對象)

可以看出這個抽象工廠模式也是有一定的缺陷的,就是每多生產一種類型商品,就得修改工廠接口和相應的工廠類,不符合我們上面說的對修改關閉,對擴展開放原則。所以這個模式適合比較穩定的模式,不能說是今天想加個蓋子,明天我又想加個勺子,然後過幾天又想加個杯墊之類的,這樣搞,工廠老闆肯定得和你拼命。。
然後是抽象工廠模式的類圖:


就這樣,李華的杯子店最後開的還是非常成功的,看完李華創業開杯子店的心路歷程,相信你一定對工廠模式有了一個更好的理解。

設計模式持續更新中。。。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章