简单聊聊Python设计模式:工厂模式

1,356 阅读4分钟

这是我参与8月更文挑战的第12天,活动详情查看:8月更文挑战

📖前言

尽我所能穷我之力,尽人事我命由我不由天。

越透明的东西越神秘,宇宙本身就是透明的,只要目力能及,你想看多远就看多远,但越看越神秘。 ----刘慈欣

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

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

💕简单工厂

首先,我们先看一个简单的例子:

#coding=utf-8
class Mercedes(object):
    """奥迪
    """
    def __repr__(self):
        return "AUDI"

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

假设我们有两个“产品”分别是AUDIBMW的汽车,如果没有“工厂”来生产它们,我们就要在代码中自己进行实例化,如:

audi = AUDI()
bmw = BMW()

但现实中,你可能会面对很多汽车产品,而且每个产品的构造参数还不一样,这样在创建实例时会遇到麻烦。这时就可以构造一个“简单工厂”把所有汽车实例化的过程封装在里面。

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

有了 SimpleCarFactory 类后,就可以通过向固定的接口传入参数获得想要的对象实例,如下:

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

🎎工厂模式:

工厂则是根据提供的不同的材料,生产出不同的产品。那么在编程的设计模式,根据提供不同的用户输入,调用相同的接口,得出不同的结果。

示例一:

在编写一个 web 框架时,我们需要考虑到用户可能会连接各种各样的数据库,但是我们不能预知用户会使用哪个数据库。于是我们提供一个通用方法,里面包含了各个数据库的连接方案,用户在使用过程中,只需要传入数据库的名字并给出连接所需要的信息,即可得到一个固定的 | 针对用户所选数据库的 | 连接字符串。

代码:

def connect(db, *arg, **kwargs):  
    db = db.lower()
    dbname = kwargs['db']

    if db == 'mysql':
        result = "mysql+pymysql://{username}:{password}@{server}/{dbname}".format(username = kwargs['username'], password = kwargs['password'], server = kwargs['server'], dbname=dbname)
    elif db == 'postgresql:
        result = 'postgresql://{username}:{passwrod}@{server}/{dbname}'.format(susername = kwargs['username'], password = kwargs['password'], server = kwargs['server'], dbname=dbname)

    return result

  可以看到:

  如果用户的输入为 'MySQL', 那么工厂方法会为其返回一个用于连接 MySQL 数据库的连接字符串;(使用 pymysql 进行连接)

  如果用户的输入为 'postgresql',那么将会得到一个用于连接 postgresql 数据库的连接字符串;更多的则是同样的原理。(安装 psycopg2 进行连接)。

 

  如上面那个示例你还没有看懂,那么继续看下面这个案例:

在实际开发过程中,分为生产模式和开发模式,那么我也可以通过工厂模式,在不同的模式下通过输出不同的命令,调用相同的接口完成 不同环境下的配置实现。

示例二:

# 在config.py模块下
class Config(object):
    # 放置两种模式下共同的配置
    pass 

class DevelopConfig(Config):
    DEBUG = True
    LOG_LEVEL = logging.DEBUG

class ProductConfig(Config):
    LOG_LEVEL = logging.ERROR


config = {
    "development": DevelopConfig,
    "production": ProductConfig
}


# __init__.py模块下
def create_app(config_name):
    app = Flask(__name__)
    app.config.from_object(config[config_name])

也就是说:当输入“development”,则加载开发环境的配置文件,而输入 “production”,则加载生产环境下的配置文件。

🎉总结

  • 其实这个方法非常初级非常暴力,就是无限的罗列需要考虑的情况并给出对应的处理而已。

  • 更多参考精彩博文请看这里:《陈永佳的博客》

  • 喜欢博主的小伙伴可以加个关注、点个赞哦,持续更新嘿嘿!