设计模式--工厂模式

在最初的学习过程中对把简单的东西搞得复杂的现象很不理解,随着经验的增长,慢慢发现我所理解的“简单”其实是针对设计的简单,这种代码缺少灵活性,目的仅仅是为了解决现有问题。而“复杂”恰恰是针对一类问题的万能方案,他可以让代码变得优雅,灵活不再是一个臃肿的胖子。

在对模式的学习过程中很容易误入歧途,陷入形式主义,对模式细节的过多关注恰恰使我们越陷越深,子曾经曰过:“学而不思则罔”,文档中的类图和实现代码往往并不能代表模式的全部,我们学习模式的重点要放在模式的意图上。

设计模式代表了最佳的实践,是开发人员在开发过程中面临一般问题的解决方案,是众多前辈们在经过相当长一段时间的试验和错误中总结出来的。

什么是设计模式

设计模式:是一套被反复使用、多数人知晓、经过分类编目的代码设计经验的总结。

使用设计模式的目的

使用设计模式是为了重用代码、让代码更容易被他人理解、保证代码的可靠性。

设计模式的分类
设计模式的分类
  • 创建型模式:创建型模式涉及对象的实例化,用于解耦对象的实例化过程,不让用户代码依赖于对象的创建或排列方式,避免用户直接使用new创建对象。。
  • 结构型模式:把类或对象结合在一起形成一个更大的结构,和类有关的结构型模式涉及如何合理使用继承机制;和对象有关的结构型模式涉及如何合理的使用对象组合机制。。
  • 行为型模式: 行为型模式涉及怎样合理的设计对象之间的交互通信,以及怎样合理为对象分配职责,让设计富有弹性,易维护,易复用。
工厂模式

意图:定义一个创建对象的接口。让其子类决定实例化哪一个类。使其实例化过程延迟到子类进行。

工厂模式中,我们在创建对象时不会对客户端暴露创建逻辑,并且是通过使用一个共同的接口来指向新创建的对象。

三个工厂
  • 简单工厂模式

简单工厂模式又叫静态工厂方法模式,实际不能算作一种设计模式。

GOF在《设计模式》一书中将工厂模式分为两类:工厂方法模式与抽象工厂模式。将简单工厂模式看为工厂方法模式的一种特例,两者归为一类。

意图:定义一个用于创建对象的接口

具体实现:
抽象一个产品基类,(接口也可以)

/**
 * @Author: chichapaofan
 * @CreateDate: 2018/10/24
 * @Description:产品的抽象类
 */
public abstract class Coffee {

    /**
     * 展示产品详情
     */
    public abstract void details();
}

产品的具体实现

/**
 * @Author: chichapaofan
 * @CreateDate: 2018/10/24
 * @Description: 美式咖啡
 */
public class Americano extends Coffee {

    @Override
    public void details() {
        System.out.print("美式咖啡,不便宜");
    }
}
/**
 * @Author: chichapaofan
 * @CreateDate: 2018/10/24
 * @Description:拿铁咖啡
 */
public class Latte extends Coffee {

    @Override
    public void details() {
        System.out.print("拿铁咖啡,不便宜");
    }
}
/**
 * @Author: chichapaofan
 * @CreateDate: 2018/10/24
 * @Description:雀巢咖啡
 */
public class Nescafe extends Coffee {

    @Override
    public void details() {
        System.out.print("雀巢咖啡,喝得起");
    }
}

简单工厂来创建不同类型的咖啡实例

/**
 * @Author: chichapaofan
 * @CreateDate: 2018/10/24
 * @Description: 简单工厂
 */
public class SimpleFactory {

    /**
     * 通过传递过来的类型创建不同实例
     * @param type
     * @return
     */
    public static Coffee createInstance(String type) {
        if (type.equals("Americano")) {
            return new Americano();
        } else if (type.equals("Latte")) {
            return new Latte();
        } else if (type.equals("Nescafe")) {
            return new Nescafe();
        } else {
            throw new RuntimeException("没有匹配到可实例化[" + type + "]对象");
        }
    }
    
}

使用

/**
 * @Author: chichapaofan
 * @CreateDate: 2018/10/24
 * @Description:
 */
public class Test {

    public static void main(String[] args) {
        Coffee latte = SimpleFactory.createInstance("Latte");
        latte.details();
        Coffee americano = SimpleFactory.createInstance("Americano");
        americano.details();
        Coffee nescafe = SimpleFactory.createInstance("Nescafe");
        nescafe.details();
    }

}

简单工厂模式在实际使用过程中,对产品部分来说是符合开闭原则的,但是对于工厂部分,每增加一个新产品,都要在工厂类中增加相应的创建逻辑,这显然违背了开闭原则。

不知道设计模式六大原则的同学请自行补课
http://www.runoob.com/design-pattern/design-pattern-intro.html

  • 工厂方法模式

意图:提供一个用于创建对象的接口(工厂接口),让其实现类(工厂实现类)决定实例化哪一个类(产品类),并且由该实现类创建对应类的实例。

可以理解为不同地区只生产自己类型的咖啡,美国America只生产Americano,德国Germany只生产Latte和Nescafe。
具体实现:
产品基类及实现同上
定义一个工厂基类,(使用接口的方式会更好)

/**
 * @Author: chichapaofan
 * @CreateDate: 2018/10/24
 * @Description:定义一个抽象咖啡工厂
 */
public abstract class CoffeeFactory {

    /**
     * 用于生产咖啡
     * @return
     */
    public abstract Coffee createCoffee(String type);
}

咖啡工厂的具体实现

/**
 * @Author: chichapaofan
 * @CreateDate: 2018/10/24
 * @Description:美国咖啡工厂
 */
public class AmericaCoffeeFactory extends CoffeeFactory{

    @Override
    public Coffee createCoffee(String type) {
        return new Americano();
    }
}
/**
 * @Author: chichapaofan
 * @CreateDate: 2018/10/24
 * @Description:德国咖啡工厂
 */
public class GermanyCoffeeFactory extends CoffeeFactory {

    @Override
    public Coffee createCoffee(String type) {
        if (type.equals("Latte")) {
            return new Latte();
        } else if (type.equals("Nescafe")) {
            return new Nescafe();
        } else {
            throw new RuntimeException("没有匹配到可实例化[" + type + "]对象");
        }
    }
}

使用

public class Test {

    public static void main(String[] args) {
        /**
         * 工厂方法模式的使用方法
         */
        CoffeeFactory americaCoffeeFactory = new AmericaCoffeeFactory();
        Coffee americaCoffees = americaCoffeeFactory.createCoffee("");
        americaCoffees.details();

        CoffeeFactory germanyCoffeeFactory = new GermanyCoffeeFactory();
        Coffee latteCoffees = germanyCoffeeFactory.createCoffee("Latte");
        latteCoffees.details();
        Coffee nescafeCoffees = germanyCoffeeFactory.createCoffee("Nescafe");
        nescafeCoffees.details();
    }
}

工厂方法模式非常符合“开闭原则”,当需要增加一个新的产品时,我们只需要增加一个具体的产品类和与之对应的具体工厂即可,无须修改原有系统。但是由于每新增一个新产品时就需要增加两个类,这样势必会导致系统的复杂度增加。

  • 抽象工厂模式

场景:当需要创建的对象是一系列相互关联或相互依赖的产品族时,便可以使用抽象工厂模式。

意图:为创建一组相关或相互依赖的对象提供一个接口,而且无需指定他们的具体类。抽象工厂为不同产品族的对象创建提供接口。
关键点在于如何在一个工厂里聚合多个同类产品。
具体实现:
抽象出饮料制造工厂

/**
 * @Author: chichapaofan
 * @CreateDate: 2018/10/24
 * @Description:
 */
public interface AbstractDrinksFactory {

    /**
     * 制造咖啡
     * @return
     */
    Coffee createCoffee();

    /**
     * 制造碳酸饮料
     * @return
     */
    Sodas createSodas();

    /**
     * 制造茶
     * @return
     */
    Tea createTea();
}

饮料工厂的具体实现

/**
 * @Author: chichapaofan
 * @CreateDate: 2018/10/24
 * @Description:美国饮料工厂
 */
public class AmericaDrinksFactory implements AbstractDrinksFactory{

    @Override
    public Coffee createCoffee() {
        return new Latte();
    }

    @Override
    public Sodas createSodas() {
        return new CocaCola();
    }

    @Override
    public Tea createTea() {
        return null;
    }
}
/**
 * @Author: chichapaofan
 * @CreateDate: 2018/10/24
 * @Description:中国饮料工厂
 */
public class ChinaDrinksFactory implements AbstractDrinksFactory{

    @Override
    public Coffee createCoffee() {
        return new Latte();
    }

    @Override
    public Sodas createSodas() {
        return new CocaCola();
    }

    @Override
    public Tea createTea() {
        return new Dragon_Well();
    }
}

使用

/**
 * @Author: chichapaofan
 * @CreateDate: 2018/10/24
 * @Description:
 */
public class Test {

    public static void main(String[] args) {
        /**
         * 抽象工厂测试
         */
        AbstractDrinksFactory chinaDrinksFactory = new ChinaDrinksFactory();
        Coffee coffee = chinaDrinksFactory.createCoffee();
        Sodas sodas = chinaDrinksFactory.createSodas();
        Tea tea = chinaDrinksFactory.createTea();
       if (coffee != null) {
            coffee.details();
        }
        if (sodas != null) {
            sodas.details();
        }
        if (tea != null) {
            tea.details();
        }
    }
}

抽象工厂模式最主要的优点就是可以在类的内部对产品族进行约束,而不必专门引入一个新的类来进行管理。
当然抽象工厂模式的缺点也非常明显,那就是产品族的不易扩展,使产品族中每需要增加一个新的产品,则几乎所有的工厂类都需要进行修改。所以使用抽象工厂模式时,对产品等级结构的划分是非常重要的。

参考文章:
http://www.runoob.com/design-pattern/abstract-factory-pattern.html
https://www.cnblogs.com/zailushang1996/p/8601808.html
https://www.cnblogs.com/carryjack/p/7709861.html

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

推荐阅读更多精彩内容

  • 设计模式概述 在学习面向对象七大设计原则时需要注意以下几点:a) 高内聚、低耦合和单一职能的“冲突”实际上,这两者...
    彦帧阅读 3,710评论 0 14
  • 设计模式——工厂模式 工厂模式核心是封装对象的创建接口,将new对象的操作封装起来,方便创建使用、管理对象。 工厂...
    Ant_way阅读 490评论 0 0
  • 设计模式汇总 一、基础知识 1. 设计模式概述 定义:设计模式(Design Pattern)是一套被反复使用、多...
    MinoyJet阅读 3,817评论 1 15
  • 今天,因为一位博友小勤的留言,我登陆了他的文学领地,大略看看文章目录,发现他来自湘西的凤凰。 终于,有人勾起我对于...
    文飞姐姐阅读 631评论 2 4
  • 认识豆先生之前,我是一只在爱情里顺风顺水的羊。 不幸的是豆先生认识我的时候,我却刚好像薅了羊毛一样的丑。 短发,粗...
    杨梓梧阅读 277评论 0 0