【23种常见程序设计模式及python实现】———— 工厂模式

系列文章目录

【23种常见程序设计模式及python实现】———— 概述
【23种常见程序设计模式及python实现】———— 单例模式



工厂模式的分类

先介绍一下三种工厂模式的分类,然后再用情景给大家展示三种模式的区别,帮助大家理解这三种模式。蓝色的文字可以暂时跳过哦

  1. 简单工厂模式定义一个创建对象的接口,将对象的创建和本身的业务逻辑分离,降低系统的耦合度,使得两个修改起来相对容易些,当以后实现改变时,只需要修改工厂类即可。
  2. 工厂方法模式 将工厂抽象化,并定义一个创建对象的接口。每增加新产品,只需增加该产品以及对应的具体实现工厂类,由具体工厂类决定要实例化的产品是哪个,将对象的创建与实例化延迟到子类,这样工厂的设计就符合“开闭原则”了,扩展时不必去修改原来的代码。
  3. 抽象工厂模式主要用于创建相关对象的家族。当一个产品族中需要被设计在一起工作时,通过抽象工厂模式,能够保证客户端始终只使用同一个产品族中的对象;并且通过隔离具体类的生成,使得客户端不需要明确指定具体生成类;所有的具体工厂都实现了抽象工厂中定义的公共接口,因此只需要改变具体工厂的实例,就可以在某种程度上改变整个软件系统的行为。

先用一句话概括一下,这三种模式从上到下逐步抽象,并且逐步更具有一般性。

情景理解

我们把自己想象成用户,我们现在需要一辆宝马车。

没有工厂的时代

因为没用工厂帮助我们,所以只能自给自足,自己创建一款宝马车,然后再拿来使用。

也许你足够厉害,完全靠自己创建了一辆宝马车。但是,如果你想要一些不同的型号呢?再重新研究,修改图纸(代码)然后再制造吗?如果要多辆汽车呢?每次制作都要重新从头造车,即使你可以克隆(复制代码)那也是个巨大的工程

简单工厂模式

后来出现了简单工厂,我们不再需要自己动手造车,可以交给工厂去创建,只需要给他一个订单(参数)。另外,因为有了工厂,我们可以通过工厂,批量制作同一型号,或者我们甚至可以通过工厂里不同的图纸制造不同型号的车辆了。

但是,这工厂不是为你一个人建造的,众口难调,宝马的型号也越来越多。一个工厂的生产显得非常吃力(你需要写很多的if或者case来满足不同型号的组装需要)

工厂方法模式

为了解决各个用户的需要,宝马公司加聘员工,成立了总部与分公司。总部(抽象类 / 接口)为每个工厂(具体的子类)提供了具体的运行规则(公共的函数),每个工厂(具体工厂类)负责创建一个系列的产品。总部是不负责生产(抽象)的,你需要根据自己的需求到不同的具体工厂进行订单。

但是后来同一款车辆出现了不同的配置,比如:空调。空调又涉及到了装或者不装。再用工厂模式的话,成本就上天了,需要创建许许多多的工厂(分别负责:523i不带空调,523i带空调,… )。而且还容易出现用户经验不足,买的空调和车辆不匹配的情况。

再作一个更形象的比方,我们需要一个 GUI 库,同时支持两种系统(windows 和 mac),库中有两种 UI 控件(checkbox 和 button) 在不同系统下 UI 有不同的形式。
如果使用工厂方法模式,用户就需要关心不同的系统调用不同的 UI 类,这样一份代码就无法满足多个系统。而且也会出现 两个系统不兼容而导致的程序错误的情况
让开发变得异常困难

抽象工厂模式

随着用户的要求越来越高,配置越来越复杂。工厂的功能也变得越来越多,工厂开始生产空调了。我们现在只需要到523i的系列工厂给销售员说:我要523i空调车,销售员就会给我们一辆523i空调车,而不需要我们专门找到523i空调车的工厂,或者先买523i再买523i的空调,然后自行组装了。

其实上面的描述已经把各种模式解决的问题都点出了(虽然使用情节没有给出代码),如果有开发经验,悟性较好的朋友应该已经理解了各个模式的区别与用途。
有的朋友可能会问,为什么我们不直接使用抽象工厂模式呢?毕竟他看上去更万能。但是别忘了,从原始的手动创造,到抽象工厂模式,时间已经过去了 n 年(不仅是我写了这么多字,更是开发成本大大升高)

代码实现(各个模式的具体实现讲解)

还是用刚才的情景,我们用代码详细实现

不使用工厂

class BMW320:
    def __init__(self):
        print('制造 => BMW320')

if __name__ == "__main__":
    bmw_320 = BMW320()

可以看到,这种方法虽然可以创造多种型号,但是随着每种型号的代码越来越长,程序的可读性和程序的出错率也会越来越高。

用户需要知道怎么创建一款车,这样子客户和车就紧密耦合在一起了,为了降低耦合,就出现了简单工厂模式,把创建宝马的操作细节都放到了工厂里,而客户直接使用工厂的创建方法,传入想要的宝马车型号就行了,而不必去知道创建的细节。

简单工厂模式

class BMW:
    def __init__(self):
        print('制造 => BMW',end = '')

class BMW320(BMW):
    def __init__(self):
        super().__init__()
        print('320')

class BMW523(BMW):
    def __init__(self):
        super().__init__()
        print('523')

class Factory:
    def __init__(self):
        pass

    def createBMW(self,tp):
        if tp == 320:
            return BMW320()
        elif tp == 523:
            return BMW523()
        else:
            return None

if __name__ == "__main__":
    bmw_factory = Factory()
    bmw_320 = bmw_factory.createBMW(320)
    bmw_523 = bmw_factory.createBMW(523)

工厂类角色Factory, 该模式的核心,用来创建产品,含有一定的商业逻辑和判断逻辑
抽象产品角色BMW 它一般是具体产品继承的父类或者实现的接口。
具体产品角色BMW320BMW523 工厂类所创建的对象就是此角色的实例。在java中由一个具体类实现。

优点

不得不说python的面向对象十分完全,实际上在强类型语言中,bmw_320bmw_523后可以用BMW类型,而且工厂bmw_factory可以自由生成多种型号的车辆。

简单工厂模式提供专门的工厂类用于创建对象,实现了对象创建和使用的职责分离,客户端不需知道所创建的具体产品类的类名以及创建过程,只需知道具体产品类所对应的参数即可,通过引入配置文件,可以在不修改任何客户端代码的情况下更换和增加新的具体产品类,在一定程度上提高了系统的灵活性。

缺点

但缺点在于不符合“开闭原则”,每次添加新产品就需要修改工厂类。随着种类的越来越多,if … elif… 越来越多,具体类也越来越多,代码越来越冗余,工厂逻辑越来越复杂,不利于系统的扩展维护,并且工厂类集中了所有产品创建逻辑,一旦不能正常工作,整个系统都要受到影响。

为了解决简单工厂模式的问题,出现了工厂方法模式。

工厂方法模式

class BMW:
    def __init__(self):
        print('制造 => BMW',end = '')

class BMW320(BMW):
    def __init__(self):
        super().__init__()
        print('320')

class BMW523(BMW):
    def __init__(self):
        super().__init__()
        print('523')

class FactoryBMW:
    def __init__(self):
        pass

    def createBMW(self):
        pass

class FactoryBMW320(FactoryBMW):
    def __init__(self):
        pass
    
    def createBMW(self):
        return BMW320()

class FactoryBMW523(FactoryBMW):
    def __init__(self):
        pass

    def createBMW(self):
        return BMW523()

if __name__ == "__main__":
    factoryBMW_320 = FactoryBMW320()
    bmw_320 = factoryBMW_320.createBMW()

    factoryBMW_523 = FactoryBMW523()
    bmw_523 = factoryBMW_523.createBMW()

抽象工厂 AbstractFactoryFactoryBMW 工厂方法模式的核心,是具体工厂角色必须实现的接口或者必须继承的父类,在 Java 中它由抽象类或者接口来实现。
具体工厂 FactoryFactoryBMW320FactoryBMW523 被应用程序调用以创建具体产品的对象,含有和具体业务逻辑有关的代码
抽象产品 AbstractProductBMW320是具体产品继承的父类或实现的接口,在 Java 中一般有抽象类或者接口来实现。
具体产品 ProductBMW523 具体工厂角色所创建的对象就是此角色的实例。

优点

生产不同车辆的具体工厂被创建,用户怎么调用的部分被移动到客户端,这样用户可以不需要知道具体怎么创建,只需要到对应的具体工厂去订单(调用)就好了,甚至不需要知道具体产品类的类名。当用户选择哪个具体工厂时,就已经决定了实际创建的产品是哪个了。

缺点

每增加一个产品都需要增加一个具体产品类和实现工厂类,使得系统中类的个数成倍增加,在一定程度上增加了系统的复杂度,同时也增加了系统具体类的依赖。

抽象工厂模式

class Engine:
    def __init__(self):
        print('配置 => Engine',end = '')

class EngineA(Engine):
    def __init__(self):
        super().__init__()
        print('A')

class EngineB(Engine):
    def __init__(self):
        super().__init__()
        print('B')

class Aircondition:
    def __init__(self):
        print('配置 => Aircondition',end = '')

class AirconditionA(Aircondition):
    def __init__(self):
        super().__init__()
        print('A')

class AirconditionB(Aircondition):
    def __init__(self):
        super().__init__()
        print('B')

class abstractFactory:
    def __init__(self):
        print('生成工厂: ',end = '')

    def createEngine(self):
        print('生产引擎: ',end = '')
    
    def createAircondition(self):
        print('生产空调: ',end = '')

class FactoryBMW320(abstractFactory): # 生产的是 BMW320 系列产品
    def __init__(self):
        super().__init__()
        print('FactoryBMW320')
    
    def createEngine(self):
        super().createEngine()
        return EngineA()

    def createAircondition(self):
        super().createAircondition()
        return AirconditionA()

class FactoryBMW523(abstractFactory): # 生产的是 BMW523 系列产品
    def __init__(self):
        super().__init__()
        print('FactoryBMW523')
    
    def createEngine(self):
        super().createEngine()
        return EngineB()
    
    def createAircondition(self):
        super().createAircondition()
        return AirconditionB()

if __name__ == "__main__":
    factory_bmw320 = FactoryBMW320()
    factory_bmw320.createEngine()
    factory_bmw320.createAircondition()

    factory_bmw523 = FactoryBMW523()
    factory_bmw523.createEngine()
    factory_bmw523.createAircondition()

先认识几个概念:

EngineAircondition
BMW320EngineAAirconditionA
BMW523EnginBAirconditionB

横向一行叫做产品族,纵向的一列叫做一个产品的等级结构

优点

通过抽象工厂模式,能够保证客户端始终只使用同一个产品族中的对象;并且通过隔离具体类的生成,使得客户端不需要明确指定具体生成类;所有的具体工厂都实现了抽象工厂中定义的公共接口,因此只需要改变具体工厂的实例,就可以在某种程度上改变整个软件系统的行为。

缺点

添加新的行为时比较麻烦,如果需要添加一个新产品族对象时,需要更改接口及其下所有子类,这必然会带来很大的麻烦。

例如:
我们还要给车辆配置音响,那么除了添加 抽象产品 Music具体产品 MusicAMusicB 以外,还需要修改 抽象工厂 abstractFactory(添加createMusic)并修改所有的 具体工厂 (实现createMusic

工厂模式小结:

工厂方法模式与抽象工厂模式的区别在于:

  1. 工厂方法只有一个抽象产品类和一个抽象工厂类,但可以派生出多个具体产品类和具体工厂类,每个具体工厂类只能创建一个具体产品类的实例。

  2. 抽象工厂模式拥有多个抽象产品类(产品族)和一个抽象工厂类,每个抽象产品类可以派生出多个具体产品类;抽象工厂类也可以派生出多个具体工厂类,同时每个具体工厂类可以创建多个具体产品类的实例

特别感谢参考文章

Java设计模式之创建型:工厂模式详解(简单工厂+工厂方法+抽象工厂)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值