设计模式之单例模式与工厂模式的Python实现(二)
2. 工厂模式
工厂模式是创建型设计模式的一种。核心的思想是,通过传递给类或函数某种产品的信息来创建产品并返回。当我们想得到产品a对象,只需把产品a的名字传递给工厂函数就能得到产品a对象。而核心思想的背后是为了遵循著名的“开闭原则”:对扩展开放,对修改封闭。当添加新功能时,对已经有的函数代码不需要修改,只需要添加新功能相关的代码即可。
举一个最简单的例子:假如我们要写一个计算器,实现加减乘除四则运算,那么最简单的方法就是写一个函数,传入运算符,然后通过switch语句(python中没有switch语句,可以想办法用字典dict代替)。但问题也是显而易见的,如果我们要添加一个新的运算,比如开平方,那么就要修改原来的包含了四则运算的函数,显然,在这个过程中容易发生错误的修改,比如不小心改到了加法运算,这会让我们原先写好的功能有被修改错误的风险。所以,对应到这个问题上,工厂模式的核心就是要把这几个运算给完全独立出来,并且不影响运算主函数(即当添加新的运算时,我们不需要修改运算主函数)。怎么做呢?其实就是创建一个工厂类,由这个工厂类通过判断传入的运算符,去对应实例化各个运算函数(或者运算类)。这样,当添加了新的运算时,我们只需要添加新的运算函数(或者运算类),和修改工厂类(即添加新的switch判断,实例化新的运算函数或者运算类)就可以了。
2.1 简单工厂模式
简单工厂模式,是最简单的工厂方法模式,其由两部分组成,一是:工厂函数或工厂类,二是:产品类(可以是多个产品类A,B,C.........)。
下面我们通过一个简单的例子来看什么是简单工厂模式:
class A(object):
def __init__(self, product_type):
self.product_type = product_type def __str__(self):
return 'product %s' % self.product_type class B(object):
def __init__(self, product_type):
self.product_type = product_type def __str__(self):
return 'product %s' % self.product_type class Factory(object):
@staticmethod
def yield_product(product_type):
if product_type == 'A':
return A(product_type)
if product_type == 'B':
return B(product_type) if __name__ == '__main__':
a = Factory.yield_product('A')
b = Factory.yield_product('B')
print(a)
print(b)
结果如下
product A
product B
上面代码中,实现了两个产品类A,B,一个工厂类Factory,工厂类中实现了一个静态方法,其实,可以用一个工厂函数来代替这个工厂类。静态方法可以通过类名进行调用,而不需把类实例化。
静态方法@staticmethod的意思是,这个方法是一个普通方法,虽然属于类,但是不用访问类的其他成员。并且可以在不把类实例化的前提下,通过类名进行调用。
2.2 工厂方法模式
简单工厂模式存在一个问题,当要增加产品时,需要修改工厂类或者工厂方法,在上面的例子中,我们需要修改工厂类的方法"yield_product"这违背了扩展开放,修改封闭的原则,因此是不可取的。工厂方法模式能够实现最小化地修改工厂类或工厂函数。
具体实现:对每一个产品类再进行一次封装,封装成只生产特定产品的工厂类。
import abc class A(object):
def __init__(self, product_type):
self.product_type = product_type def __str__(self):
return 'product %s' % self.product_type class B(object):
def __init__(self, product_type):
self.product_type = product_type def __str__(self):
return 'product %s' % self.product_type class Abstract_factory(object):
__metaclass__ = abc.ABCMeta @abc.abstractmethod
def yield_product(self):
pass class Factory_a(Abstract_factory): def yield_product(self):
return A('A') class Factory_b(Abstract_factory): def yield_product(self):
return B('B') def factory(product_type):
if product_type == 'A':
return Factory_a()
if product_type == 'B':
return Factory_b() if __name__ == '__main__':
factory_a = factory('A')
a = factory_a.yield_product()
factory_b = factory('B')
b = factory_b.yield_product()
print(a)
print(b)
结果如下
product A
product B
上述代码,Factory_a,Factory_b是对类A,B的封装,一个工厂只负责创建一个产品遵从了单一职责原则,有利于代码的扩展和维护。
其中@abc.abstractmethod表示被该装饰器修饰的方法是一个抽象方法,没有实现,所以该基本不能被实例化。只有子类实现了该抽象方法才能被实例化。
参考链接:
1. python 设计模式(三) 工厂模式 https://blog.csdn.net/ruguowoshiyu/article/details/80657052
2. Python中的staticmethod与classmethod
3. python中@classmethod @staticmethod区别
4. Python2和Python3中@abstractmethod的用法 https://blog.csdn.net/xiemanR/article/details/72629164
设计模式之单例模式与工厂模式的Python实现(二)的更多相关文章
- 设计模式之单例模式与工厂模式的Python实现(一)
1. 单例模式 单例模式(Singleton Pattern)是一种常用的软件设计模式,该模式的主要目的是确保某一个类只有一个实例存在.当你希望在整个系统中,某个类只能出现一个实例时,单例对象就能派上 ...
- 10月27日PHP加载类、设计模式(单例模式和工厂模式)、面向对象的六大原则
加载类可以使用include.require.require_once三种中的任意一种,每个关键字都有两种方法,但是这种方法的缺点是需要加载多少个php文件,就要写多少个加载类的方法.一般也就需要加载 ...
- php部分---面向对象,设计模式(单例模式、工厂模式)、oop六大原则;
一.单例模式目的:为了控制对象的数量(只能够有一个,相当于类的计划生育)做法1.将类的构造函数做成私有的2.在类里面做了一个公有的函数来造对象3.将该函数变为静态的4.在函数里面加控制 class R ...
- java:常用的两种设计模式(单例模式和工厂模式)
一.单例模式:即一个类由始至终只有一个实例.有两种实现方式(1)定义一个类,它的构造方法是私有的,有一个私有的静态的该类的变量在初始化的时候就实例化,通过一个公有的静态的方法获取该对象.Java代码 ...
- PHP模式设计之单例模式、工厂模式、注册树模式、适配器模式、观察者模式
php模式设计之单例模式 什么是单例模式? 单例模式是指在整个应用中只有一个实例对象的设计模式 为什么要用单例模式? php经常要链接数据库,如果在一个项目中频繁建立连接数据库,会造成服务器资源的很大 ...
- headfirst设计模式(5)—工厂模式体系分析及抽象工厂模式
先编一个这么久不写的理由 上周我终于鼓起勇气翻开了headfirst设计模式这本书,看看自己下一个设计模式要写个啥,然后,我终于知道我为啥这么久都没写设计模式了,headfirst的这个抽象工厂模式, ...
- java设计模式-----1、简单工厂模式
简单工厂模式是属于创建型模式,又叫做静态工厂方法(Static Factory Method)模式,但不属于23种GOF设计模式之一.简单工厂模式是由一个工厂对象决定创建出哪一种产品类的实例,简单来说 ...
- Java设计模式(1)工厂模式(Factory模式)
工厂模式定义:提供创建对象的接口. 为何使用工厂模式 工厂模式是我们最常用的模式了,著名的Jive论坛,就大量使用了工厂模式,工厂模式在Java程序系统可以说是随处可见. 为什么工厂模式是如此常用?因 ...
- 工厂模式的python实现
#1.什么是工厂模式 #2.工厂模式的分类 ''' 1. 简单工厂模式 2. 工厂方法模式 3. 抽象工厂方法模式 ''' #3.简单工厂模式的python实现 from abc import ABC ...
随机推荐
- babel 不能统编译Iterator、Generator、Set、Maps、Proxy、Reflect、Symbol、Promise的问题
Babel默认只转换新的JavaScript句法(syntax),而不转换新的API,比如Iterator.Generator.Set.Maps.Proxy.Reflect.Symbol.Promis ...
- C编程经验总结4
{}体里的语句不管在一行还是在多行,之间都是要有: for与for之间可以是独立的,也可以是相互嵌套的 For( ; i<5; )=for( ;i<=4; ) 一般都是在循环里面进行判断 ...
- vue2.0之监听属性的使用心得及搭配计算属性的使用
我们在工作中常常需要监听某一个属性值的变化,这个时候我们就需要用到了监听属性watch,在这里我总结watch属性的三种场景使用希望对你有所帮助: 1.基础版监听: 场景如下:输入框输入你的年龄,如果 ...
- 线段树的应用xx中学模拟lites
跟昨天那个自己写的,没有按照模板来的一看风格就不相类似,今天模拟赛的时候就是用的我的那个自己YY的代码,才拿了10分.个人认为关键的问题应该在于对于数据的处理太过繁琐了,所以回来之后,就拿了大佬的程序 ...
- 利用python在windows环境下爬取赶集网工作信息。
主要用到了多进程和多线程的知识,最后结果保存成csv文件格式,如有需要可改成数据库版本. 对用到的库做下简要介绍,具体请参考官方文档: xpinyin.Pinyin:将输入的中文转成拼音 concur ...
- thinkphp5,单图,多图,上传
/** * 上传单图 */ function upload($path, $filename) { $file = request()->file($filename); $info = $fi ...
- FreeBSD--常用命令
FreeBSD常用命令 查看网络流量 a.systat -if 1 (1表示1s刷新屏幕一次) b.netstat 1 # Traffic 流量 peak 峰值 average 平均值 查看进程p ...
- 微信小程序插件内页面跳转和参数传递
在此以插件开发中文章列表跳传文章详情为例. 1.首先在插件中的文章列表页面wxml中绑定跳转事件. bindtap='url' data-id="{{item.article_id}}&qu ...
- MySQL基础 (麦子学员 php 第二阶段)
通过my.ini配置文件修改字符集:客户端字符集设置:[mysql]default-character-set=utf8 [mysqld] character-set-server=utf8 .设置之 ...
- ORA-01122: 数据库文件 1 验证失败
1.SQL>shutdown abort 如果数据库是打开状态,强行关闭 2.SQL>sqlplus / as sysdba 3.SQL>startupORACLE 例程已经启动. ...