用Python实现设计模式——工厂模式

前言

工厂模式,顾名思义就是咱们能够经过一个指定的“工厂”得到须要的“产品”,在设计模式中主要用于抽象对象的建立过程,让用户能够指定本身想要的对象而没必要关心对象的实例化过程。这样作的好处是用户只需经过固定的接口而不是直接去调用类的实例化方法来得到一个对象的实例,隐藏了实例建立过程的复杂度,解耦了生产实例和使用实例的代码,下降了维护的复杂性。
本文会用Python实现三种工厂模式的简单例子,全部代码都托管在Github上。html

简单工厂

首先,咱们先看一个简单工厂的例子:python

#coding=utf-8
class Mercedes(object):
    """梅赛德斯
    """
    def __repr__(self):
        return "Mercedes-Benz"

class BMW(object):
    """宝马
    """
    def __repr__(self):
        return "BMW"

假设咱们有两个“产品”分别是MercedesBMW的汽车,若是没有“工厂”来生产它们,咱们就要在代码中本身进行实例化,如:git

mercedes = Mercedes()
bmw = BMW()

但现实中,你可能会面对不少汽车产品,并且每一个产品的构造参数还不同,这样在建立实例时会遇到麻烦。这时就能够构造一个“简单工厂”把全部汽车实例化的过程封装在里面。github

class SimpleCarFactory(object):
    """简单工厂
    """
    @staticmethod
    def product_car(name):
        if name == 'mb':
            return Mercedes()
        elif name == 'bmw':
            return BMW()

有了SimpleCarFactory类后,就能够经过向固定的接口传入参数得到想要的对象实例,以下:数据库

c1 = SimpleCarFactory.product_car('mb')
c2 = SimpleCarFactory.product_car('bmw')

工厂方法

虽然有了一个简单的工厂,但在实际使用工厂的过程当中,咱们会发现新问题:若是咱们要新增一个“产品”,例如Audi的汽车,咱们除了新增一个Audi类外还要修改SimpleCarFactory内的product_car方法。这样就违背了软件设计中的开闭原则[1],即在扩展新的类时,尽可能不要修改原有代码。因此咱们在简单工厂的基础上把SimpleCarFactory抽象成不一样的工厂,每一个工厂对应生成本身的产品,这就是工厂方法。设计模式

#coding=utf-8
import abc

class AbstractFactory(object):
    """抽象工厂
    """
    __metaclass__ = abc.ABCMeta

    @abc.abstractmethod
    def product_car(self):
        pass

class MercedesFactory(AbstractFactory):
    """梅赛德斯工厂
    """
    def product_car(self):
        return Mercedes()

class BMWFactory(AbstractFactory):
    """宝马工厂
    """
    def product_car(self):
        return BMW()

咱们把工厂抽象出来用abc模块[2]实现了一个抽象的基类AbstractFactory,这样就能够经过特定的工厂来得到特定的产品实例了:网络

c1 = MercedesFactory().product_car()
c2 = BMWFactory().product_car()

每一个工厂负责生产本身的产品也避免了咱们在新增产品时须要修改工厂的代码,而只要增长相应的工厂便可。如新增一个Audi产品,只需新增一个Audi类和AudiFactory类。字体

抽象工厂

工厂方法虽然解决了咱们“修改代码”的问题,但若是咱们要生产不少产品,就会发现咱们一样须要写不少对应的工厂类。好比若是MercedesFactoryBMWFactory不只生产小汽车,还要生产SUV,那咱们用工厂方法就要再多构造两个生产SUV的工厂类。因此为了解决这个问题,咱们就要再更进一步的抽象工厂类,让一个工厂能够生产同一类的多个产品,这就是抽象工厂。具体实现以下:设计

#coding=utf-8
import abc

# 两种小汽车
class Mercedes_C63(object):
    """梅赛德斯 C63
    """
    def __repr__(self):
        return "Mercedes-Benz: C63"

class BMW_M3(object):
    """宝马 M3
    """
    def __repr__(self):
        return "BMW: M3"

# 两种SUV
class Mercedes_G63(object):
    """梅赛德斯 G63
    """
    def __repr__(self):
        return "Mercedes-Benz: G63"

class BMW_X5(object):
    """宝马 X5
    """
    def __repr__(self):
        return "BMW: X5"

class AbstractFactory(object):
    """抽象工厂
    能够生产小汽车外,还能够生产SUV
    """
    __metaclass__ = abc.ABCMeta

    @abc.abstractmethod
    def product_car(self):
        pass

    @abc.abstractmethod
    def product_suv(self):
        pass

class MercedesFactory(AbstractFactory):
    """梅赛德斯工厂
    """
    def product_car(self):
        return Mercedes_C63()

    def product_suv(self):
        return Mercedes_G63()

class BMWFactory(AbstractFactory):
    """宝马工厂
    """
    def product_car(self):
        return BMW_M3()

    def product_suv(self):
        return BMW_X5()

咱们让基类AbstractFactory同时能够生产汽车和SUV,而后令MercedesFactoryBMWFactory继承AbstractFactory并重写product_car和product_suv方法便可。日志

c1 = MercedesFactory().product_car()
s1 = MercedesFactory().product_suv()
print(c1, s1)
s2 = BMWFactory().product_suv()
c2 = BMWFactory().product_car()
print(c2, s2)

抽象工厂模式与工厂方法模式最大的区别在于,抽象工厂中的一个工厂对象能够负责多个不一样产品对象的建立 ,这样比工厂方法模式更为简单、有效率。

结论

初学设计模式时会对三种工厂模式的实际应用比较困惑,其实三种模式各有优缺点,应用的场景也不尽相同:

  • 简单工厂模式适用于需建立的对象较少,不会形成工厂方法中的业务逻辑太过复杂的状况下,并且用户只关心那种类型的实例被建立,并不关心其初始化过程时,好比多种数据库(MySQL/MongoDB)的实例,多种格式文件的解析器(XML/JSON)等。
  • 工厂方法模式继承了简单工厂模式的优势又有所改进,其再也不经过一个工厂类来负责全部产品的建立,而是将具体建立工做交给相应的子类去作,这使得工厂方法模式能够容许系统可以更高效的扩展。实际应用中能够用来实现系统的日志系统等,好比具体的程序运行日志,网络日志,数据库日志等均可以用具体的工厂类来建立。
  • 抽象工厂模式在工厂方法基础上扩展了工厂对多个产品建立的支持,更适合一些大型系统,好比系统中有多于一个的产品族,且这些产品族类的产品需实现一样的接口,像不少软件系统界面中不一样主题下不一样的按钮、文本框、字体等等。

参考

[1]维基百科
[2]Python官方文档


2018/1/30更新:修改工厂方法的代码示例,新增结论一节。

相关文章
相关标签/搜索