美文网首页
设计模式(五)——简单工厂模式

设计模式(五)——简单工厂模式

作者: X_Meteor | 来源:发表于2019-04-28 10:00 被阅读0次

    前言

    前面我们学习了相对简单的 原型模式 今天就让我们一起来学习下另外一个很简单的模式:简单工厂模式

    按照惯例我们先看下工厂的概念

    工厂:又称制造厂,是一所用以生产货物的大型工业楼宇。大部分工厂皆设有以大型机器或设备构成的生产线。

    解决了什么问题:

    我们都知道,现实中的工厂解决的是生产力低下的问题。那软件中的工厂呢?

    软件中的工厂其实跟现实中的工厂很像,都是为了解决创建产品的问题。

    现实中的工厂,我们扔进去材料,工厂生产成产品,我们不需要管他怎么生产的只要拿到最后的产品就行了。

    软件里的工厂,我们扔进去参数,工厂生产出来对象,我们也不需要中的他是怎么实例化的,只要最后拿到相应对象就行了。

    GOF在《设计模式》一书中将工厂模式分为两类:工厂方法模式(Factory Method)与抽象工厂模式(Abstract Factory)。

    将简单工厂模式(Simple Factory)看为工厂方法模式的一种特例,两者归为一类。今天我们就先条软柿子捏,从简单工厂模式入手。

    按照惯例我们先摆出今天的内容要点:

    通过这篇文章你能学到什么

    (建议你可以带着问题去学习)

    1、简单工厂模式的定义;
    2、简单工厂模式的写法;
    3、简单工厂模式的使用场景;
    4、简单工厂模式的优缺点;

    上面我们已经了解了简单工厂的概念和工厂在日常生活中的解释,我们再来看软件工程中简单工厂模式的定义:

    简单工厂模式(Simple Factory Pattern):定义一个工厂类,它可以根据参数的不同返回不同类的实例,被创建的实例通常都具有共同的父类。因为在简单工厂模式中用于创建实例的方法是静态(static)方法,因此简单工厂模式又被称为静态工厂方法(Static Factory Method)模式,它属于类创建型模式。

    我们一起来分析一下简单工厂模式的定义,可以看到,简单工厂模式的要点在于:

    当你当你需要什么,只需要传入一个正确的参数,就可以获取你所需要的对象,而无须知道其创建细节。简单工厂模式结构比较简单,其核心是工厂类的设计。

    简单解释就是:我给你传参,你给我对象。我不需要管你是怎么创建的。

    简单工程模式的类图

    简单工厂模式的类图如下:

    简单工厂模式类图.jpg

    通过类图我们可以看到,简单工厂模式主要是有三个角色:Factory(工厂角色)、Product(抽象产品角色)、ConcreteProduct(具体产品角色),接下来我们先分别认识一下这三个角色:

    Factory(工厂角色):工厂角色即工厂类,它是简单工厂模式的核心,负责实现创建所有产品实例的内部逻辑;工厂类可以被外界直接调用,创建所需的产品对象;在工厂类中提供了静态的工厂方法factoryMethod(),它的返回类型为抽象产品类型Product。

    Product(抽象产品角色):它是工厂类所创建的所有对象的父类,封装了各种产品对象的公有方法,它的引入将提高系统的灵活性,使得在工厂类中只需定义一个通用的工厂方法,因为所有创建的具体产品对象都是其子类对象。

    ConcreteProduct(具体产品角色):它是简单工厂模式的创建目标,所有被创建的对象都充当这个角色的某个具体类的实例。每一个具体产品角色都继承了抽象产品角色,需要实现在抽象产品中声明的抽象方法。

    看完类图和成员介绍不知道大家有没有对简单工厂模式有一个更深刻的认识?

    什么还没有,好吧。那接下来我们通过一个具体的代码例子来加深一下印象。

    简单的例子

    我们都知道可口可乐公司生产了很多饮料,雪碧、芬达、肥仔快乐水等;那这些饮料肯定都是通过饮料工厂来生产的,那我们就用简单工厂模式来实现一下这个场景:

    抽象产品:Produce —— 饮料
    具体产品:ConcreteProduct —— 具体饮料
    工厂:Factory —— 饮料工厂

    /**
     * @description: 饮料——抽象产品
     */
    interface BeveragesProduct {
    
        /**
         * @description: 获取饮料名称
         * @date:
         * @company:
         * @author: Meteor
         */
        fun getBeveragesName()
    
        /**
         * @description: 设置饮料配方
         * @date:
         * @company:
         * @author: Meteor
         */
        fun getBeveragesRecipe()
    }
    
    
    
    /**
     * @description: 可乐 —— 具体产品
     */
    class Coke : BeveragesProduct {
    
        override fun getBeveragesName() {
            println("我是可乐:别名肥仔快乐水")
        }
    
        override fun getBeveragesRecipe() {
            println("配方:水,二氧化碳,可乐糖浆")
        }
    
    }
    
    /**
     * @description: 芬达 —— 具体产品
     */
    class Fanta :BeveragesProduct{
        override fun getBeveragesName() {
            println("我是芬达")
        }
    
        override fun getBeveragesRecipe() {
            println("配方:水,二氧化碳,芬达糖浆")
        }
    }
    
    
    /**
     * @description: 雪碧 —— 具体产品
     */
    class Sprite : BeveragesProduct {
        override fun getBeveragesName() {
            println("我是雪碧")
        }
    
        override fun getBeveragesRecipe() {
            println("配方:水,二氧化碳,雪碧糖浆")
        }
    }
    
    /**
     * @description: 饮料工厂 —— 工厂
     */
    class BeveragesFactory {
    
        companion object {
            val TYPE_COKE = 1
            val TYPE_FANTA = 2
            val TYPE_SPRITE = 3
    
            fun getBeverages(type: Int): BeveragesProduct? {
                var beveragesProduct: BeveragesProduct? = null
                when (type) {
                    TYPE_COKE -> {
                        beveragesProduct = Coke()
                    }
                    TYPE_FANTA -> {
                        beveragesProduct = Fanta()
                    }
                    TYPE_SPRITE -> {
                        beveragesProduct = Sprite()
                    }
                }
                return beveragesProduct
            }
        }
    
    }
    
    
    /**
     * @description: 肥仔,老喝碳酸饮料
     */
    class Fatty {
    
        companion object {
            @JvmStatic
            fun main(args: Array<String>) {
                //通过往工厂传类型,获取具体对象
                val beveragesProduct: BeveragesProduct? = BeveragesFactory.getBeverages(BeveragesFactory.TYPE_COKE)
                beveragesProduct?.getBeveragesName()
                beveragesProduct?.getBeveragesRecipe()
            }
        }
    }
    

    工作中使用的场景

    简单工厂模式在工作中有很多应用的地方,具体在哪里使用,参照下面两个因素就可以了:

    1、工厂类负责创建的对象比较少,由于创建的对象较少,不会造成工厂方法中的业务逻辑太过复杂。
    2、客户端只知道传入工厂类的参数,对于如何创建对象并不关心。

    优点

    简单工厂模式的优点主要有以下几点:

    1、 工厂类包含必要的判断逻辑,可以决定在什么时候创建哪一个产品类的实例,客户端可以免除直接创建产品对象的职责,而仅仅“消费”产品,简单工厂模式实现了对象创建和使用的分离。

    2、 客户端无须知道所创建的具体产品类的类名,只需要知道具体产品类所对应的参数即可,对于一些复杂的类名,通过简单工厂模式可以在一定程度减少使用者的记忆量。

    3、通过引入配置文件,可以在不修改任何客户端代码的情况下更换和增加新的具体产品类,在一定程度上提高了系统的灵活性。

    缺点

    当然简单工厂模式也有它的缺点:

    1、由于工厂类集中了所有产品的创建逻辑,职责过重,一旦不能正常工作,整个系统都要受到影响。

    2、使用简单工厂模式势必会增加系统中类的个数(引入了新的工厂类),增加了系统的复杂度和理解难度。

    3、系统扩展困难,一旦添加新产品就不得不修改工厂逻辑,在产品类型较多时,有可能造成工厂逻辑过于复杂,不利于系统的扩展和维护。

    4、简单工厂模式由于使用了静态工厂方法,造成工厂角色无法形成基于继承的等级结构。

    总结

    其实简单工厂模式还是相对比较好理解的,通俗点说就是把我们之前各种通过 if 判断后创建的对象,封装了起来(因为工厂里面也是通过if判断的),不过把这块单独抽离了出来,做了解耦方便我们维护和管理。

    简单工厂模式属于工厂模式和抽象工厂模式的基础,先学好这个对学习后面两个有帮助。

    设计模式目录

    设计模式(一)—— 认识设计模式
    设计模式(二)—— 技术直男正确“面向对象”的六大原则
    设计模式(三)—— 单例模式
    设计模式(四)—— 原型模式
    设计模式(五)—— 简单工厂模式

    参考资料

    《设计模式——可复用面向对象软件的基础》
    《Head First设计模式》
    《大话设计模式》
    《设计模式之禅》
    《Android 源码设计模式解析与实战》

    刘伟

    相关文章

      网友评论

          本文标题:设计模式(五)——简单工厂模式

          本文链接:https://www.haomeiwen.com/subject/gwgxgqtx.html