设计模式系列--工厂模式

工厂模式是一种创建者模式,在任何生成复杂对象的地方都可以使用工厂模式。理论来说在任何使用A a = new A()的方式都可以使用工厂模式,虽然使用工厂模式可能需要多做一些工作,但是在后续的开发和维护都带来了方便。

如果我们需要在构建对象的时候,需要做很多的处理工作,比如初始化工作,查询工作等一些耗时的工作,如果我们将这些操作全部放入到构造方法中去写,那么势必在后期维护的带来不方便,而且始化工作如果是很长一段代码,说明要做的工作很多,将很多工作装入一个方法中,相当于将很多鸡蛋放在一个篮子里,是很危险的,这也是有悖于Java面向对象的原则,面向对象的封装(Encapsulation)和分派(Delegation)告诉我们,尽量将长的代码分派“切割”成每段,将每段再“封装”起来(减少段和段之间耦合联系性),这样,就会将风险分散,以后如果需要修改,只要更改每段,不会再发生牵一动百的事情。

工厂模式分类、

  • 简单工厂模式

  • 工厂模式

  • 抽象工厂模式

    三者之间的区别:

  1. 工厂方法模式只有一个抽象产品类,而抽象工厂模式有多个。
  2. 工厂方法模式的具体工厂类只能创建一个具体产品类的实例,而抽象工厂模式可以创建多个。
  3. 简单工厂模式只有一个抽象产品类,一个工厂类

简单工厂模式

简单工厂模式的UML图


factory1.png
  • Factory : 负责生产具体的产品工厂
  • Product: 抽象的产品类,
  • P1: 具体的产品类P1
  • P2: 具体的产品类P2

汽车工厂造汽车的例子。首先Rrtoyewx在大众厂里面上班,一开始被分配到了上海大众里面去了,只管Passat和polo两款车型,而且做的事很简单,就是简单开出去测试一下车子的性能。这个时候事务较少,Rrtoyewx觉得用简单工厂就能搞定了。

具体的代码:
产品类
Volkswagen

public interface Volkswagen {
    void drive();

    String getName();
}

Passat

public class Passat implements Volkswagen {
    public static final int ID = 0;

    @Override
    public void drive() {
        System.out.println("Passat开出去咯,测试成功");  
    }

    @Override
    public String getName() {
        return "Passat";
    }
}

Polo

public class Polo implements Volkswagen{
    public static final int ID = 1;

    @Override
    public void drive() {
        System.out.println("Polo开出去咯,测试成功");
    }

    @Override
    public String getName() {
        return "Polo";
    }
}

工厂类

public class ShangHaiVolkswagenFactory {

    public Volkswagen createVolkswagen(int id){
        Volkswagen volkswagen = null;
        switch(id){
            case Passat.ID:
                volkswagen = new Passat();
                break;
            case Polo.ID:
                volkswagen = new Polo();
                break;
            default:
                volkswagen = null;
        }
        return volkswagen;
    }
}

客户端类

public class Client {
    public static void main(String[] args) {
        ShangHaiVolkswagenFactory factory = new ShangHaiVolkswagenFactory();

        Volkswagen passat = factory.createVolkswagen(Passat.ID);
        passat.drive();

        Volkswagen polo = factory.createVolkswagen(Polo.ID);
        System.out.println(polo.getName());
    }
}

每次测试的时候Client类都跑了一遍,似乎很简单,同样的也方便以后的扩展(添加新的车型的时候),只需要添加一个产品类,然后在工厂里添加响应的逻辑就行了。Rrtoyewx觉得自己这个测试车辆程序完全够用了。

简单工厂模式优缺点

优点:客户端需要的什么产品,可以直接得到,逻辑判断在工厂里面,
缺点:扩展性一般,产品都是一个产品族下面的产品,对于不在产品族中的产品,没办法去扩展,另外获得具体某种产品的逻辑放在工厂里面,新添加产品的时候就需要修改工厂里面的代码。

工厂模式

  • 一个抽象产品,派生出去多种具体的产品的
  • 一个抽象工厂,派生出多种生产产品的工厂类
  • 一个具体的工厂负责生产一种具体的产品


    factory2.png
  • AbstractProduct:抽象的产品类
  • ProductA:具体的A产品
  • ProductB:具体的B产品
  • AbstractFactory:抽象工厂类
  • FactoryA:具体的生产A产品的工厂类
  • FactoryB:具体的生产B产品的工厂类
  • Client: 客户端类

举个栗子

还是上面的栗子的。Rrtoyewx在负责上海大众的两款车型,本来就着简单工厂的模式测试车辆的时候,日子过的非常好,可是好景不长,突然有一天领导说Rrtoyewx说:一汽大众厂最近较忙,看你比较清闲,你就顺便把一汽大众的迈腾,和速腾都测一下。本来Rrtoyewx觉得挺简单的,就是简单再添加一个Magotan和Sagitar,然后通过工厂生成就行了,可是等Rrtoyewx一拿到测试的项目的时候,发现并不是只测试drive,Sagitar和Magotan不仅需要测试drive,而且需要测试brake。好吧,Rrtoyewx觉得以前写的都不能够用了。想了很久,Rrtoyewx 觉得需要将简单工厂模式升级到工厂模式,关注点也发生了改变不再为具体的车辆的,而是一汽大众的车(Magotan和Sagitar)还是上海大众的车(Passat和 Polo)了

具体的代码和介绍
抽象类
产品类
Volkswagen类,将Volkswagen类转成抽象类

public abstract class Volkswagen {
    public abstract void drive();
    public abstract String getName();
}

ShangHaiVolkswagen:上海大众汽车的抽象类

public abstract class ShangHaiVolkswagen implements Volkswagen{

}

FAWVolkswagen : 一汽大众汽车的抽象类,多了一个brake()的方法

public abstract class FAWVolkswagen implements Volkswagen {
    public abstract void brake();
}

工厂类
VolkswagenFactory : 汽车工厂的抽象类,并将createVolkswagen(Class clazz)声明称final类型。供子类使用

public abstract class VolkswagenFactory {

    public abstract Volkswagen createVolkswagen(int productID);

    public final Volkswagen createVolkswagen(Class <? extends Volkswagen> clazz){
        Volkswagen volkswagen = null;
        try {
            volkswagen = clazz.newInstance();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
        return volkswagen;
    };
}

实现类:
产品类
上海大众的具体实现类 Passat类

public class Passat extends ShangHaiVolkswagen {
    public static final int ID = 0;

    @Override
    public void drive() {
        System.out.println("Passat开出去咯,测试成功");  
    }

    @Override
    public String getName() {
        return "Passat";
    }
}

Polo类

public class Polo extends ShangHaiVolkswagen{
    public static final int ID = 1;

    @Override
    public void drive() {
        System.out.println("Polo开出去咯,测试成功");
    }

    @Override
    public String getName() {
        return "Polo";
    }
}

一汽大众的汽车类。 Sagitar类,

public class Sagitar extends FAWVolkswagen {
    public static final int ID = 2;

    @Override
    public void drive() {
        System.out.println("Sagitar 开出去了,测试成功了");
    }

    @Override
    public String getName() {
        return "Sagitar";
    }

    @Override
    public void brake(){
        System.out.println("Sagitar 刹车挺好的,测试通过了");
    }
}

Magotan 类

public class Magotan extends FAWVolkswagen{
    public static final int ID = 3;

    @Override
    public void drive() {
        System.out.println("Magotan 开出去咯,测试成功了");
    }

    @Override
    public String getName() {
        return "Magotan";
    }

    @Override
    public void brake(){
        System.out.println("Magotan 刹车挺好的,测试通过");
    }
}

工厂类
注意重载方法的返回类型已经修改称对应的产品类,不在是Volkswagen类型了 ShangHaiVolkswagenFactory:负责生产上海汽车的工厂类

public class ShangHaiVolkswagenFactory extends VolkswagenFactory {

    public ShangHaiVolkswagen createVolkswagen(int id){
        ShangHaiVolkswagen volkswagen = null;
        switch(id){
            case Passat.ID:
                volkswagen = new Passat();
                break;
            case Polo.ID:
                volkswagen = new Polo();
                break;
            default:
                volkswagen = null;
        }
        return volkswagen;
    }
}

FAWVolkswagenFactory:负责生产一汽汽车的工厂类

public class FAWVolkswagenFactory extends VolkswagenFactory {

    @Override
    public FAWVolkswagen createVolkswagen(int productID) {
        FAWVolkswagen volkswagen = null;
        switch(productID){
            case Magotan.ID:
                volkswagen = new Magotan();
                break;
            case Sagitar.ID:
                volkswagen = new Sagitar();
                break;
            default:
                volkswagen = null;
        }
        return volkswagen;
    }
}

Client类:用来测试

public class Client {
    public static void main(String[] args) {
        System.out.println("开始测试上海大众的车辆");
        ShangHaiVolkswagenFactory factory = new ShangHaiVolkswagenFactory();
        ShangHaiVolkswagen passat = factory.createVolkswagen(Passat.ID);
        passat.drive();

        ShangHaiVolkswagen polo = factory.createVolkswagen(Polo.ID);
        polo.drive();

        System.out.println("开始测试一汽大众的车辆");
        FAWVolkswagenFactory fawFactory = new FAWVolkswagenFactory();

        FAWVolkswagen magotan = fawFactory.createVolkswagen(Magotan.ID);
        magotan.drive();
        magotan.brake();
        FAWVolkswagen sagitar = fawFactory.createVolkswagen(Sagitar.ID);
        sagitar.drive();
        sagitar.brake();
    }
}

打印log的也能够正确的测试:
这里写图片描述

通过下面的改变,Rrtoyewx将工厂抽象出生产上海大众的车子和一汽大众的车子的两个工厂,并将一汽大众和上海大众的车子做了区分,形成两个不同产品族的产品系列。并由两个工厂分别对应去生产。等Rrtoyewx做完了这么多后,终于发现原先的系统还是有漏洞的,还是有局限性的,好在及时的弥补。Rrtoyewx发现现有的系统无论处理一汽大众的车子还是上海大众的车子,甚至于再加一个进口大众工厂的车子也够用了。再以后的扩展也能得到了提升了。

工厂模式的优缺点

优点:扩展性,能够处理不同产品系列的产品,通过具体的工厂去生成不同产品族的产品,扩展性较好。
缺点:类的个数较多。另外一个工厂的只能够生产一个具体的产品。

抽象工厂类

  • 多个抽象产品类
  • 每个抽象产品类可以派生出多个具体产品类
  • 一个抽象工厂类,可以派生出多个具体工厂类
  • 每个具体工厂类可以创建多个具体产品类的实例
image.png
  • AbstractFactory:抽象工厂类
  • ConcreteFactoryA:具体工厂A,负责生产A和B的
  • ConcreteFactoryB:具体工厂b,负责生产A和B的
  • AbstractProductA,AbstractProductB:抽象的产品类
  • ConcreteProductA1,ConcreteProductA2:具体产品A
  • ConcreteProductB1,ConcreteProductB2:具体产品B
  • Client:客户端

总结

  1. 工厂模式是一个创建型的模式
  2. 在任何使用A a = new A()的情况下,理论上说都能使用工厂模式。
  3. 在工厂模式分别的对应使用中,简单工厂模式,注重具体生成的产品,而工厂模式,注重的同一个产品下的不同产品族的产品。如栗子中上海大众的汽车和一汽大众的汽车,抽象工厂模式更多事在与整体产品的架构上,不再是单一一个的抽象产品类。
  4. 工厂模式:一个抽象产品派生出去多个具体的产品,一个抽象工厂派生出多个具体的工厂,而一个具体的工厂对应生成的是一个具体的产品。
  5. 抽象工厂模式:多个抽象产品分别派生出多个具体的产品,一个抽象工厂派生成出多个具体的工厂,一个工厂对应生成多个具体的产品,这些多个抽象产品之间存在着联系。

参考博客:http://blog.csdn.net/zhi184816/article/details/51348567

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

推荐阅读更多精彩内容