转载自 SegmentFault作者 夏秋, https://segmentfault.com/a/1190000013053013

非常感谢这位作者的深入浅出的讲解.

前言

工厂模式,顾名思义就是我们可以通过一个指定的“工厂”获得需要的“产品”,在设计模式中主要用于抽象对象的创建过程,让用户可以指定自己想要的对象而不必关心对象的实例化过程。这样做的好处是用户只需通过固定的接口而不是直接去调用类的实例化方法来获得一个对象的实例,隐藏了实例创建过程的复杂度,解耦了生产实例和使用实例的代码,降低了维护的复杂性。
本文会用Python实现三种工厂模式的简单例子,所有代码都托管在Github上。

简单工厂

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

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

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

 mercedes = Mercedes()
bmw = BMW()

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

 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模块实现了一个抽象的基类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)等。
  • 工厂方法模式继承了简单工厂模式的优点又有所改进,其不再通过一个工厂类来负责所有产品的创建,而是将具体创建工作交给相应的子类去做,这使得工厂方法模式可以允许系统能够更高效的扩展。实际应用中可以用来实现系统的日志系统等,比如具体的程序运行日志,网络日志,数据库日志等都可以用具体的工厂类来创建。
  • 抽象工厂模式在工厂方法基础上扩展了工厂对多个产品创建的支持,更适合一些大型系统,比如系统中有多于一个的产品族,且这些产品族类的产品需实现同样的接口,像很多软件系统界面中不同主题下不同的按钮、文本框、字体等等。

转载 用Python实现设计模式——工厂模式的更多相关文章

  1. Python与设计模式--工厂模式

    快餐点餐系统 想必大家一定见过类似于麦当劳自助点餐台一类的点餐系统吧.在一个大的触摸显示屏上,有3类可以选择的上餐品:汉堡等主餐.小食.饮料.当我们选择好自己需要的食物,支付完成后,订单就生成了.下面 ...

  2. 设计模式-工厂模式(Factory Pattern)

    本文由@呆代待殆原创,转载请注明出处. 工厂模式遵循的设计原则之一:找出代码中常变化的部分,并把这一部分分离出来.(Dependency Inversion Principle) 工厂模式简述 当我们 ...

  3. .NET设计模式: 工厂模式

    .NET设计模式: 工厂模式(转) 转自:http://www.cnblogs.com/bit-sand/archive/2008/01/25/1053207.html   .NET设计模式(1): ...

  4. python实现简单工厂模式

    python实现简单工厂模式 模式定义 简单工厂模式(Simple Factory Pattern):又称为静态工厂方法(Static Factory Method)模式,它属于类创建型模式.在简单工 ...

  5. 【设计模式】Java设计模式 -工厂模式

    [设计模式]Java设计模式 -工厂模式 不断学习才是王道 继续踏上学习之路,学之分享笔记 总有一天我也能像各位大佬一样 一个有梦有戏的人 @怒放吧德德 分享学习心得,欢迎指正,大家一起学习成长! 目 ...

  6. 大话设计模式Python实现- 抽象工厂模式

    抽象工厂模式(Abstract Factory Pattern):提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们的类 下面是一个抽象工厂的demo: #!/usr/bin/env pyth ...

  7. 浅谈Python设计模式 - 工厂模式

    声明:本系列文章主要参考<精通Python设计模式>一书,并且参考一些资料,结合自己的一些看法来总结而来. 工厂模式: 顾名思义,工厂则是根据提供的不同的材料,生产出不同的产品.那么在编程 ...

  8. 大话设计模式Python实现-简单工厂模式

    简单工厂模式(Simple Factory Pattern):是通过专门定义一个类来负责创建其他类的实例,被创建的实例通常都具有共同的父类. 下面使用简单工厂模式实现一个简单的四则运算 #!/usr/ ...

  9. 设计模式——工厂模式(Factory)

    要想正确理解设计模式,首先必须明白它是为了解决什么问题而提出来的. 设计模式学习笔记 --Shulin 转载请注明出处:http://blog.csdn.net/zhshulin 1.概念 工厂模式定 ...

随机推荐

  1. tomcat/Java指定加载jar包的路径

    背景:部署的web站点,应用默认加载工程的/webapps/工程名/WEB-INF/lib下的jar包   但是我需要提供一个和web工程没关系的的jar包管理目录   解决方法: 执行java方法时 ...

  2. 小强学渲染之OpenGL渲染管线详析

    什么是OpenGL? OpenGL是一套图形硬件的软件API接口库,它直接和GPU交互,将3D场景渲染绘制到2D屏幕上.总结说,OpenGL的功能是将程序中定义的各种2D或3D模型绘制到帧缓存中,或者 ...

  3. oracle 新增并返回新增的主键

    oracle 的insert into 语句需要返回新增的主键的时候,可以使用一下insert 语法: insert into ims.t_bank_inquire_results (t_date,l ...

  4. jq获取图片并转换为base64

    html代码: <input type="file" id="file1"/> jq代码: $('#file1').change(function( ...

  5. Python数据分析--Pandas知识点(三)

    本文主要是总结学习pandas过程中用到的函数和方法, 在此记录, 防止遗忘. Python数据分析--Pandas知识点(一) Python数据分析--Pandas知识点(二) 下面将是在知识点一, ...

  6. Django-ConttentType

    一 content-type 在django中,有一个记录了项目中所有model元数据的表,就是ContentType,表中一条记录对应着一个存在的model,所以可以通过一个ContentType表 ...

  7. 线程的使用方法start run sleep join

    今天回顾了Java的线程的一些知识 例1:下面代码存有详细的解释 主要是继承Thread类与实现Runnable接口 以及start()和run()方法 package com.date0607; / ...

  8. elk kibana查询语法

    elk日志系统中kibana查询语法 单项term查询 例: 搜 Dahlen, Malone 字段field查询 field:value 例:city:Keyport, age:26 通配符 ? 匹 ...

  9. 多进程和mongo的配合使用

    这篇文章主要是讲在多线程下使用mongo数据库的一个报错,算是一个警告,如下: /usr/lib64/python2.6/site-packages/pymongo/topology.py:75: U ...

  10. Jmeter利用CSV Data Set Config 和 _CSVRead函数实现参数化

    测试接口时,当请求参数不是固定的,每次请求对应的参数都是不同的,就需要对请求参数进行参数化.我们这里简单介绍一下5个用户与一个用户建立好友关系. 一.测试需求描述 1. 本次测试的接口为http服务端 ...