创建型模式---工厂模式

工厂模式

在工厂设计模式中,客户端可以请求一个对象,而无需要知道这个对象来自哪里,也就是使用哪个类来生成这个对象。工厂背后的思想是简化对象的创建。与客户端自己基于类实例化直接创建对象相比,基于一个中心化函数来实现,更易于追踪创建了那些对象。
工厂通常有两种形式:一种是工厂方法,它是一个方法(函数),对不同的输入参数返回不同的对象;第二种是抽象工厂,它是一组用于创建一系列相关事物对象的工厂方法。

工厂方法

在工厂方法模式中,我们执行单个函数,传入一个参数(提供信息表明我们想要什么),但不要求直到任何关于对象如何实现以及对象来自哪里的细节。
现实生活中的例子:塑料玩具制造制造塑料玩具的压塑粉都是一样的,但是使用不同塑料模具就能产出不同的外形。比如有一个工厂方法,输入是目标外形的名称,输出则是要求的塑料外形。
软件中的例子:Django框架使用工厂方法模式来创建表单字段。Django的forms模块支持不同种类字段(CharField,EmailField)的创建和制定(max_length,required)。
应用案例:
如果因为应用创建对象的代码分布在多个不同的地方,而不是仅在一个函数/方法中,你发现没法跟踪这些对象,那么应该考虑使用工厂方法模式。工厂方法集中地在一个地方创建对象,使对象跟踪变得更容易。

案例实现

以下例子将关注两种流行的人类可读文件格式:XML和JSON。
在当前这个问题中,我们有一些输入数据存储在一个XML文件和JSON文件中,要对这两个文件进行解析,获取一些信息。同时,希望对这些(以及将来涉及的的所有)外部服务进行集中式的客户端连接。我们使用工厂方法来解决这个问题。
#数据来源:
json文件:http://opensource.adobe.com/Spry/samples/data_region/JSONDataSetSample.html#Example4
xml文件:https://en.wikipedia.org/wiki/JSON#XML
import xml.etree.ElementTree as etree
import json#类JSONConnector解析JSON文件,通过parsed_data()方法以一个字典dict的形式返回数据
class JSONConnector:def __init__(self,filepath):self.data = {}with open(filepath,mode='r',encoding='utf-8') as f:self.data = json.load(f)@propertydef parsed_data(self):return self.data#类XMLConnector解析XML文件,通过parsed_data()方法以xml.etree.Element列表的形式返回所有数据。
class XMLConnector:def __init__(self,filepath):self.tree = etree.parse(filepath)@propertydef parsed_data(self):return self.tree#工厂方法connect_factory,基于输入路径的扩展名返回一个JSONConnector或XMLConnector的实例
def connect_factory(filepath):if filepath.endswith('json'):connector = JSONConnectorelif filepath.endswith('xml'):connector = XMLConnectorelse:raise ValueError('Cannot connect to {}'.format(filepath))return connector(filepath)#函数connnect_to对工厂方法进行包装,添加了异常处理
def connect_to(filepath):factory = Nonetry:factory = connect_factory(filepath)except ValueError as e:print(e)return factorydef main():sqlite_factory = connect_to('person.sq3')print()xml_factory = connect_to('test2.xml')xml_data = xml_factory.parsed_dataliars = xml_data.findall(".//{}[{}='{}']".format('person','lastName','Liar'))for liar in liars:print('first name:{}'.format(liar.find('firstName').text))print('last name:{}'.format(liar.find('lastName').text))[print('phone number ({}):'.format(p.text)) for p in liar.find('phoneNumber')]#待完善XML模式匹配语法print()json_factory = connect_to('test1.json')json_data = json_factory.parsed_dataprint('found:{} donuts'.format(len(json_data)))for donut in json_data:print('name:{}'.format(donut['name']))print('price:${}'.format(donut['ppu']))[print('topping:{}{}'.format(t['id'],t['type'])) for t in donut['topping']]if __name__ == '__main__':main()

抽象工厂

抽象工厂设计模式是抽象方法的一种泛化。概括来说,一个抽象工厂是(逻辑上的)一组工厂方法,其中每个工厂方法负责产生不同种类的对象。
现实生活中的例子:汽车制造业应用了抽象工厂的思想。冲压不同汽车模型的部件(车门、仪表盘、车篷以及挡泥板的等)所使用的的机件是相同的。机件组装起来的模型随时可配置,且易于改变。
软件中的例子:程序包django_factory是一个用于在测试中创建Django模型的抽象工厂实现,可用来为支持测试专有属性的模型创建实例。这能让测试代码的可读性更高,且能避免共享不必要的代码,故有其存在的价值。
应用案例:
抽象工厂模式是工厂方法模式的一种泛化,所以它能提供相同的好处:让对象的创建更容易追踪;将对象创建与使用解耦;提供优化内存占用和应用性能的潜力。
那我们何时使用工厂方法,何时又该使用抽象工厂?答案是,通常一开始使用工厂方法,因为它更简单。如果后来发现应用需要许多工厂方法,那么会将创建一些列对象的过程合并在一起更合理,从而最终引入抽象工厂。
#想象一下,我们正在创造一个游戏,或者想在应用中包含一个迷你游戏让用户娱乐一下。我们希望至少包含两个游戏,一个面向孩子,一个面向大人。在运行时,基于用户输入,决定该创建那个游戏并运行。游戏的创建部分由一个抽象工厂维护。
class Frog:def __init__(self,name):self.name = namedef __str__(self):return self.namedef interact_with(self,obstacle):print('{} the Frog encounters {} and {}!'.format(self,obstacle,obstacle.action()))class Bug:def __str__(self):return 'a bug'def action(self):return 'eats it'#抽象工厂FrogWorld,其主要职责是创建游戏的主人公和障碍物。
class FrogWorld:def __init__(self,name):print(self)self.player_name = namedef __str__(self):return '\n\n\t------ Frog World ------'def make_character(self):return Frog(self.player_name)def make_obstacle(self):return Bug()class Wizard:def __init__(self,name):self.name = namedef __str__(self):return self.namedef interact_with(self,obstacle):print('{} the wizard battles against {} and {}!'.format(self,obstacle,obstacle.action()))class Ork:def __str__(self):return 'a evil ork'def action(self):return 'kills it'#抽象工厂WizardWorld,类似于FrogWorld
class WizardWorld:def __init__(self,name):print(self)self.player_name = namedef __str__(self):return '\n\n\t------ Wizard World ------'def make_character(self):return Wizard(self.player_name)def make_obstacle(self):return Ork()#类GameEnvironment是我们游戏的主入口,它接受factory作为输入,用其创建游戏的世界。
class GameEnvironment:def __init__(self,factory):self.hero = factory.make_character()self.obstacle = factory.make_obstacle()def play(self):self.hero.interact_with(self.obstacle)#validate_age提示用户输入一个有效的年龄
def validate_age(name):try:age = input('Welcome {}.How old are you?'.format(name))age = int(age)except ValueError as err:print("Age {} is invalid,please try again...".format(age))return (False,age)return (True,age)def main():name = input("Hello,What's your name?")valid_input = Falsewhile not valid_input:valid_input,age = validate_age(name)game = FrogWorld if age<18 else WizardWorldenvironment = GameEnvironment(game(name))environment.play()if __name__ == '__main__':main()

小结

工厂方法设计模式的实现是一个不属于任何类的单一函数,负责单一种类对象的创建。
抽象工厂设计模式的实现是同属于单个类的许多个工厂方法用于创建一系列种类的相关对象。

 

转载于:https://www.cnblogs.com/xiaoshayu520ly/p/10978424.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/448809.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

OpenCL memory object 之 Global memory (2)

当我们用clCreateBuffer, clCreateImage创建OpenCL memory object时候&#xff0c;我们需要输入一个flag参数&#xff0c;这个参数决定memory object的位置。 cl_mem clCreateBuffer (cl_context context, cl_mem_flags flags, size_t size, void *host_ptr, cl_int *errc…

数据结构进阶篇-跳表

大家想必都知道&#xff0c;数组和链表的搜索操作的时间复杂度都是O(N)的&#xff0c;在数据量大的时候是非常耗时的。对于数组来说&#xff0c;我们可以先排序&#xff0c;然后使用二分搜索&#xff0c;就能够将时间复杂度降低到O(logN)&#xff0c;但是有序数组的插入是一个O…

查看本机ssh公钥,生成公钥

前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到教程。 查看ssh公钥方法&#xff1a; 1.通过命令窗口&#xff1a;打开你的git bash 窗口&#xff0c;进入.ssh目录&#xff1a;cd ~/.ssh&…

如何实现动态水球图 --》 echars结合echarts-liquidfill实现

1&#xff09;项目中作为项目依赖&#xff0c;安装到项目当中(注意必须要结合echars) npm install echarts vue-echarts --save npm install echarts-liquidfill --save 2&#xff09;在需要使用水晶球的组件里引入liquidFill.js import echarts-liquidfill/src/liquidFill.js;…

OpenCL memory object 之选择传输path

对应用程序来说&#xff0c;选择合适的memory object传输path可以有效提高程序性能。 下面先看一写buffer bandwidth的例子&#xff1a; 1. clEnqueueWriteBuffer()以及clEnqueueReadBuffer() 如果应用程序已经通过malloc 或者mmap分配内存&#xff0c;CL_MEM_USE_HOST_PTR是个…

struts入门超详细

https://blog.csdn.net/yerenyuan_pku/article/details/52652262转载于:https://www.cnblogs.com/liuna369-4369/p/10870873.html

RabbitMQ 从入门到精通 (一)

目录 1. 初识RabbitMQ2. AMQP3.RabbitMQ的极速入门4. Exchange(交换机)详解4.1 Direct Exchange4.2 Topic Exchange4.3 Fanout Exchange5. Message 消息1. 初识RabbitMQ RabbitMQ 是一个开源的消息代理和队列服务器&#xff0c;用来通过普通协议在完全不同的应用之间共享数据&a…

接收并解析消息体传参、解析 json 参数

前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到教程。 1.场景&#xff1a;postman 发送了一个 post 请求&#xff0c;如下&#xff1a; 2. 解析方式为用一个 vo 对象来接收 json。把 json 中的…

OpenCL memory object 之 传输优化

首先我们了解一些优化时候的术语及其定义&#xff1a; 1、deferred allocation&#xff08;延迟分配&#xff09;&#xff0c; 在第一次使用memory object传输数据时&#xff0c;runtime才对memory object真正分配空间。 这样减少了资源浪费&#xff0c;但第一次使用时要慢一些…

VBS使文本框的光标位于所有字符后

有时候在文本框里会显示一部分提示信息&#xff0c;用户在这些提示信息后面输入文本&#xff0c;但是将焦点设置于文本框后&#xff0c;光标总是在文本框的最前面&#xff0c; 用户输入的时候需要按"-->"键将光标移到最后才能输入&#xff0c;这样的操作很不爽。我…

记录ionic 最小化应用时所遇的问题

ionic3与ionic4最小化插件安装不一样&#xff1a; ionic3安装方法&#xff1a; $ ionic cordova plugin add cordova-plugin-appminimize $ npm install --save ionic-native/app-minimize4 并在app.module.ts中 注入依赖&#xff1a; import { AppMinimize } from ionic-nativ…

解决 --- Docker 启动时报错:iptables:No chain/target/match by the name

问题&#xff1a;jenkins的docker containner启动失败&#xff0c;报错&#xff1a;failed programming external connectivity … iptables: No chain/target/match by that name” docker 服务启动的时候&#xff0c;docker服务会向iptables注册一个链&#xff0c;以便让dock…

AMD OpenCL 大学课程

AMD OpenCL大学课程是非常好的入门级OpenCL教程&#xff0c;通过看教程中的PPT&#xff0c;我们能够很快的了解OpenCL机制以及编程方法。下载地址&#xff1a;http://developer.amd.com/zones/OpenCLZone/universities/Pages/default.aspx 教程中的英文很简单&#xff0c;我相信…

第一篇 计算机基础

1.什么是编程语言 python和中文、英语一样、都是一门语言&#xff0c;只要是语言&#xff0c;其实就库看成是一种事物与另一种事物沟通的介质。python属于编程语言&#xff0c;编程语言是程序员与计算机之间沟通的介质&#xff1b;中文和英文则是人与人之间沟通的介质。 2.什么…

47.QT-QChart之曲线图,饼状图,条形图使用

1.使用准备 在pro中, 添加QT charts 然后在界面头文件中添加头文件并声明命名空间,添加: #include <QtCharts> QT_CHARTS_USE_NAMESPACE 2.QChart之曲线图 绘制曲线图需要用到3个类 QSplineSeries: 用于创建有由一系列数据组成的曲线.类似的还有QPieSeries(饼图数据). Q…

Docker 部署应用、jar 工程 docker 方式部署

前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到教程。 1. 把要部署的工程打成一个jar包。&#xff08;我的工程叫 gentle &#xff09; 打 jar 的方法&#xff1a;超简单方法&#xff1a; Int…

流浪不是我的初衷 ... ...

前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到教程。 或许&#xff0c;我从来就是一个习惯沉默的人 ... 或许&#xff0c;我从来就不善于倾述 ... 会有难过的时候&#xff0c;会有觉得累的…

第二阶段冲刺(2)

1、整个项目预期的任务量 &#xff08;任务量 所有工作的预期时间&#xff09;和 目前已经花的时间 &#xff08;所有记录的 ‘已经花费的时间’&#xff09;&#xff0c;还剩余的时间&#xff08;所有工作的 ‘剩余时间’&#xff09; &#xff1b; 所有工作的预期时间&#…

VS2008+OpenCL环境配置

1. 配置.cl文件支持: 1.1. 打开VS2008&#xff0c; 工具->选项->文本编辑器->文件扩展名&#xff0c;添加一个新的扩展名&#xff0c;指定编辑器为Microsoft Visual C 。这样在OpenCL文件中就能显示C的语法高亮了。 1.2. 配置OpenCL语法高亮 - 打开目录~\NVIDIA Corpo…

第十二周学习进度报告

代码时间&#xff1a;17小时左右&#xff0c; 代码量&#xff1a;300行左右&#xff0c; 阅读&#xff1a;一个app的诞生20页&#xff1b;构建之法30页 知识&#xff1a;抽象典型用户&#xff08;具有代表性&#xff09;和场景&#xff0c;去设计相应功能。 转载于:https://www…