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();
    }
}
------------------------------
运行结果:
我正在使用陶瓷杯子。。。
我是一只陶瓷杯盖
我正在使用玻璃杯子。。。
我是一只玻璃杯盖
我正在使用撸撸杯。。。
我是一只撸撸杯盖
------------------------------

可以看到这个模式与之前的工厂方法模式有所不同,每个工厂不只生产一种商品,而是生产一个系列,或者说是一套的东西。我们称之为抽象工厂模式

抽象工厂模式:
提供一个创建一系列相关或相互依赖对象的接口,而无须指定它们具体的类。( 在抽象工厂模式中,每一个具体工厂都提供了多个工厂方法用于产生多种不同类型的对象)

可以看出这个抽象工厂模式也是有一定的缺陷的,就是每多生产一种类型商品,就得修改工厂接口和相应的工厂类,不符合我们上面说的对修改关闭,对扩展开放原则。所以这个模式适合比较稳定的模式,不能说是今天想加个盖子,明天我又想加个勺子,然后过几天又想加个杯垫之类的,这样搞,工厂老板肯定得和你拼命。。
然后是抽象工厂模式的类图:


抽象工厂模式

就这样,李华的杯子店最后开的还是非常成功的,看完李华创业开杯子店的心路历程,相信你一定对工厂模式有了一个更好的理解。

设计模式持续更新中。。。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,293评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,604评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,958评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,729评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,719评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,630评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,000评论 3 397
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,665评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,909评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,646评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,726评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,400评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,986评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,959评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,197评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,996评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,481评论 2 342