设计模式之工厂模式

工厂模式:

当创建逻辑比较复杂时,就可以考虑使用工厂模式,封装对象的创建过程,将对象的创建和使用相分离。

工厂模式,属于创建类型

实际代码我放在了Github: https://github.com/liangtengyu/DesignPatterns-for-Java

应用场景:

学习一个设计模式之前 我们先了解它的使用场景能够帮我们更快的理解它,
相对于直接 new 来创建对象,用工厂模式来创建究竟有什么好处呢?

主要有两种情况:

  • 第一种情况是类似规则配置解析的例子,代码中存在 if-else 分支判断,动态的根据不同的类型创建不同的对象。针对这种情况,我们就可以考虑使用工厂模式,将这一大块的 if-else 创建对象的代码抽离出来,放到工厂类中。

  • 还有一种情况是,尽管我们不需要根据不同的类型创建不同的对象,但是,单个对象本身的创建过程比较复杂,我们也可以考虑使用工厂模式。

好处:由于工厂模式是依靠抽象架构的,它把实例化产品的任务交由实现类完成,扩展性比较好。也就是说,当需要系统有比较好的扩展性时,可以考虑工厂模式,不同的产品用不同的实现工厂来组装。通俗的讲就是降低代码改变对产品功能的影响.

实现方式:

简单工厂(Simple Factory)

首先,我们来看,什么是简单工厂模式。我们通过一个例子来解释一下。

简单工厂模式

public class Cocacola implements Cola {
    public String getCola() {
        return "可口可乐";
    }
}
public class ColaFactory {

    public static Cola getInstance(Integer  colaType) {
        if (1 == colaType) {
            return new Cocacola();
        } else if (2 == colaType) {
            return new Pepsicola();
        } else {
            return new Fakecola();
        }
    }

}
 public static void main(String[] args) {
        String drink = ColaFactory.getInstance(1).drink();
        System.out.println(drink);
    }
    //可口可乐

尽管简单工厂模式的代码实现中,有多处 if 分支判断逻辑,违背开闭原则,但权衡扩展性和可读性,这样的代码实现在大多数情况下是没有问题的。

工厂方法(Factory Method)

工厂方法是简单工厂的进一步的延伸,这样说是因为简单工厂违反了开闭原则,而此时工厂方法却可以完美的解决这个问题!接下来看看它是怎么解决的吧!

[工厂方法 - 项目](file:/Users/tengyu/IdeaProjects/designs/factory/src/main/java/factoryMethod)

对于规则配置文件解析这个应用场景来说,工厂模式需要额外创建诸多 Factory 类,也会增加代码的复杂性,而且,每个 Factory 类只是做简单的 new 操作,功能非常单薄(只有一行代码),也没必要设计成独立的类,所以,在这个应用场景下,简单工厂模式好用,比工厂方法模式更加合适

public interface ColaFactory {//工厂接口
    Cola getCola();
}
public class CocaColaFactoryImpl implements ColaFactory {//实现可口可乐工厂
    public Cola getCola() {
        return  new Cocacola();
    }
}
public static void main(String[] args) {
    //工厂方法需要一个可乐时,直接去对应的工厂拿,而是不像简单工厂那样 都是从一个工厂中根据判断来拿
    //每一种可乐都对应一个工厂
    ColaFactory pepsiColaFactory = new PepsiColaFactoryImpl();
    Cola cola = pepsiColaFactory.getCola();
    cola.getCola();
}

什么时候该用工厂方法模式,而非简单工厂模式呢?

    之所以将某个代码块剥离出来,独立为函数或者类,原因是这个代码块的逻辑过于复杂,剥离之后能让代码更加清晰,更加可读、可维护。

    但是,如果代码块本身并不复杂,就几行代码而已,我们完全没必要将它拆分成单独的函数或者类。基于这个设计思想,当对象的创建逻辑比较复杂,不只是简单的 new 一下就可以,而是要组合其他类对象,做各种初始化操作的时候,我们推荐使用工厂方法模式,将复杂的创建逻辑拆分到多个工厂类中,让每个工厂类都不至于过于复杂。而使用简单工厂模式,将所有的创建逻辑都放到一个工厂类中,会导致这个工厂类变得很复杂。

    除此之外,在某些场景下,如果对象不可复用,那工厂类每次都要返回不同的对象。如果我们`使用简单工厂模式来实现`,`就只能选择第一种包含 if 分支逻辑的实现方式`。如果我们还想避免烦人的 if-else 分支逻辑,这个时候,我们就推荐使用工厂方法模式。

抽象工厂(Abstract Factory)

抽象工厂模式的应用场景比较特殊,没有前两种常用,我们简单了解一下

简单工厂只是对可乐产品进行了抽象,工厂方法是对可乐工厂进行抽象,抽象工厂是对工厂方法的再次抽象

光从概念可能不好理解,我们来个实例

需求:现在产品线调整了,我们生产的可乐 虽然有各自的品牌但是都是透明瓶子,我们要做出自己的特点.需要给不同品牌的可乐喷涂不同的颜色瓶身.

思考:如果此时我们将可乐的生产和颜色的喷涂都耦合在工厂方法的代码中,后续调整会很麻烦,也违背了开闭原则,对拓展开放,对修改关闭,那么此时我们使用抽象工厂就比较合适了

public abstract class ColaAbstractFactory {//创建抽象工厂类
    abstract ColaFactory getCola(String cola);
    abstract ColorFactory getColor(String color);
}
public class ColaAbstractFactoryImpl extends ColaAbstractFactory {

        //实现抽象类
   public ColaFactory getCola(String cola) {
        if ("cocacola".equals(cola)) {
            return new CocaColaFactoryImpl();
        } else if ("fake".equals(cola)) {
            return new FakeColaFactoryImpl();
        } else if ("pepsi".equals(cola)) {
            return new PepsiColaFactoryImpl();
        } else
            return null;
    }

    public ColorFactory getColor(String color) {
        if ("yellow".equals(color)) {
            return new YellowColorFactoryImpl();
        } else if ("blue".equals(color)) {
            return new BlueColorFactoryImpl();
        } else if ("red".equals(color)) {
            return new RedColorFactoryImpl();
        } else
            return null;
    }
}
public class RedColorFactoryImpl implements ColorFactory {//对不同颜色的需求进行喷涂.其它颜色类似就不重复贴了
    public String getColor() {
        System.out.println("喷涂红色瓶身");
        return "红色瓶子";
    }
}

最终我们想要获得可乐+红色瓶身

public static String getColaAndColor(String cola,String color){
    ColaAbstractFactoryImpl colaAbstractFactory = new ColaAbstractFactoryImpl();

    ColaFactory cola = colaAbstractFactory.getCola(cola);
    ColorFactory red = colaAbstractFactory.getColor(color);

    Cola col = cola.getCola();
    String colo = red.getColor();
    return col.getCola()+"-"+colo;
}
public static void main(String[] args) {
    String colaAndColor = FactoryProducer.getColaAndColor("cocacola", "red");
    System.out.println(colaAndColor);

}
//output:
喷涂红色
生产可口可乐
可口可乐-红色瓶子

关注公众号:java宝典

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

推荐阅读更多精彩内容