Python——工厂模式
前言
工厂模式,顾名思义就是我们可以通过一个指定的“工厂”获得需要的“产品”.
在设计模式中主要用于抽象对象的创建过程,让用户可以指定自己想要的对象而不必关心对象的实例化过程。
这样做的好处是用户只需通过固定的接口而不是直接去调用类的实例化方法来获得一个对象的实例,隐藏了实例创建过程的复杂度,解耦了生产实例和使用实例的代码,降低了维护的复杂性。
一.简单工厂
首先,我们先看一个简单工厂的例子:
#!/usr/bin/env python
# ~*~ coding: utf-8 ~*~
class Mercedes(object):
"""梅赛德斯
"""
def __repr__(self):
return "Mercedes-Benz"
class BMW(object):
"""宝马
"""
def __repr__(self):
return "BMW"
假设我们有两个“产品”分别是Mercedes和BMW的汽车,如果没有“工厂”来生产它们,我们就要在代码中自己进行实例化,如:
#!/usr/bin/env python
# ~*~ coding: utf-8 ~*~
mercedes = Mercedes()
bmw = BMW()
场景一: 但现实中,你可能会面对很多汽车产品,而且每个产品的构造参数还不一样,这样在创建实例时会遇到麻烦。这时就可以构造一个“简单工厂”把所有汽车实例化的过程封装在里面。
#!/usr/bin/env python
# ~*~ coding: utf-8 ~*~
class SimpleCarFactory(object):
"""简单工厂
"""
@staticmethod
def product_car(name):
if name == 'mb':
return Mercedes()
elif name == 'bmw':
return BMW()
有了SimpleCarFactory类后,就可以通过向固定的接口传入参数获得想要的对象实例,如下:
#!/usr/bin/env python
# ~*~ coding: utf-8 ~*~
c1 = SimpleCarFactory.product_car('mb')
c2 = SimpleCarFactory.product_car('bmw')
二.工厂方法
虽然有了一个简单的工厂,但在实际使用工厂的过程中,我们会发现新问题:
场景二: 如果我们要新增一个“产品”,例如Audi的汽车,我们除了新增一个Audi类外还要修改SimpleCarFactory内的product_car方法。这样就违背了软件设计中的开闭原则[1],即在扩展新的类时,尽量不要修改原有代码。所以我们在简单工厂的基础上把SimpleCarFactory抽象成不同的工厂,每个工厂对应生成自己的产品,这就是工厂方法。
#!/usr/bin/env python
# ~*~ coding: utf-8 ~*~
import abc
class AbstractFactory(object):
"""抽象工厂
"""
__metaclass__ = abc.ABCMeta
@abc.abstractmethod
def product_car(self):
pass
class Mercedes(object):
"""梅赛德斯
"""
def __repr__(self):
return "Mercedes-Benz"
class BMW(object):
"""宝马
"""
def __repr__(self):
return "BMW"
class MercedesFactory(AbstractFactory):
"""梅赛德斯工厂
"""
def product_car(self):
return Mercedes()
class BMWFactory(AbstractFactory):
"""宝马工厂
"""
def product_car(self):
return BMW()
我们把工厂抽象出来用abc模块[2]实现了一个抽象的基类AbstractFactory,这样就可以通过特定的工厂来获得特定的产品实例了:
#!/usr/bin/env python
# ~*~ coding: utf-8 ~*~
c1 = MercedesFactory().product_car()
c2 = BMWFactory().product_car()
每个工厂负责生产自己的产品也避免了我们在新增产品时需要修改工厂的代码,而只要增加相应的工厂即可。如新增一个Audi产品,只需新增一个Audi类和AudiFactory类。
抽象工厂
工厂方法虽然解决了我们“修改代码”的问题,
场景三: 但如果我们要生产很多产品,就会发现我们同样需要写很多对应的工厂类。比如如果MercedesFactory和BMWFactory不仅生产小汽车,还要生产SUV,那我们用工厂方法就要再多构造两个生产SUV的工厂类。所以为了解决这个问题,我们就要再更进一步的抽象工厂类,让一个工厂可以生产同一类的多个产品,这就是抽象工厂。具体实现如下:
#!/usr/bin/env python
# ~*~ 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,然后令MercedesFactory和BMWFactory继承AbstractFactory并重写product_car和product_suv方法即可。
#!/usr/bin/env python
# ~*~ coding: utf-8 ~*~
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官方文档
3.用Python实现设计模式——工厂模式
Python——工厂模式的更多相关文章
- 设计模式 -创建型模式 ,python工厂模式 抽象工厂模式(1)
工厂模式 import xml.etree.ElementTree as etree import json class JSONConnector: def __init__(self, filep ...
- [python实现设计模式]-3.简单工厂模式-触宝开放平台
预备知识: 开放封闭原则(Open-Closed Principle OCP) Software entities(classes,modules,functions etc) should open ...
- 抽象工厂模式(python版)
http://blog.csdn.net/ponder008/article/details/6886039 抽象工厂模式:提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类.优点:易 ...
- Python: 设计模式 之 工厂模式例(2)(神奇的Python)
#!/usr/bin/env python #coding=utf-8 # # 工厂模式第二例(神奇的Python) # 版权所有 2014 yao_yu (http://blog.csdn.net/ ...
- Python: 设计模式 之 工厂模式例(1)
#!/usr/bin/env python #coding=utf-8 # # 工厂模式一例 # 版权所有 2014 yao_yu (http://blog.csdn.net/yao_yu_126) ...
- python设计模式---创建型之工厂模式
# coding = utf-8 from abc import ABCMeta, abstractmethod # 简单工厂模式 class Animal(metaclass=ABCMeta): @ ...
- python实现简单工厂模式
python实现简单工厂模式 模式定义 简单工厂模式(Simple Factory Pattern):又称为静态工厂方法(Static Factory Method)模式,它属于类创建型模式.在简单工 ...
- 转载 用Python实现设计模式——工厂模式
转载自 SegmentFault作者 夏秋, https://segmentfault.com/a/1190000013053013 非常感谢这位作者的深入浅出的讲解. 前言 工厂模式,顾名思义就是我 ...
- [Python设计模式] 第1章 计算器——简单工厂模式
github地址:https://github.com/cheesezh/python_design_patterns 写在前面的话 """ 读书的时候上过<设计模 ...
随机推荐
- 一个http的Post请求问题,unable to resolve host <我的域名>:no address associated with hostnam
原因:你应用中写入的测试服务器地址baseURL解析不了,服务器端设置的原因: 解决:找服务端修改设置,或者Android应用中把测试地址改为上线服务器地址.
- python开发常见应用第一卷(OS遍历文件并存储文件路径到数据库)
之前我们爬取完指定网站的图片后,会将它门保存到服务器或本地的数据库中,真正的工作中大多数是采用分布式的方式来爬取的,所以这些图片会分布在很多的主机上面,当被引用时需要根据IP+图片路径来引用并且加载, ...
- supervisor安装与配置实践版
应用场景 系统:centos7 需求:监控一个swooleWebSocket.php文件,程序使用的是8080端口,挂了自动被supervisor拉起来 一.首先要安装supervisor软件 yum ...
- Spring @Column的注解详解
就像@Table注解用来标识实体类与数据表的对应关系类似,@Column注解来标识实体类中属性与数据表中字段的对应关系. 该注解的定义如下: @Target({METHOD, FIELD}) @Ret ...
- 吴裕雄--天生自然python学习笔记:python的Bokeh 基本绘图
使用 Bokeh 绘图时,其大部分绘图功能是由 bokeh plotting 完成的,所以我们一 般至少要导入自gure 及 show 这两个函数 : Bokeh 绘制的图形是在浏览器中显示的, 创建 ...
- The Pomodoro Technique
目录 简介 What to solve How to use Some applications 自我总结 结束语 简介 番茄工作法是简单易行的时间管理方法,是由弗朗西斯科·西里洛于1992年创立的一 ...
- 第一课 安装wamp环境
1.准备 怎样选择PHP的版本 IIS 如果想使用IIS配置PHP的话,那么需要选择Non-Thread Safe(NTS)版本的PHP Apache 如果你是用的Apache的版本来自Apache ...
- flink测试用例编写
使用tableFunction的collect总是npe, 实际可以自定义collector, 在collector中做自己想做的事 不使用现成的collector
- u盘出现大文件无法复制的解决
如果u盘出现大文件无法复制的情况,修改U盘的文件系统格式: 把U盘格式化为NTFS格式. FAT32的都不能放4G+的文件;右键格式化里如果没有NTFS,就在开始运行里输入cmd 然后输入" ...
- 使用 Commitizen 撰写 Angular 规范的 commit message
本文为原创文章,转载请标明出处 目录 安装及配置 使用 1. 安装及配置 npm install -g commitizen npm install -g cz-conventional-change ...