python设计模式笔记1:创建型模式 工厂模式和抽象工厂模式

news2024/12/24 20:35:42

1.工厂模式

(1) 导入所需的模块( json 和 ElementTree )。
(2) 定义 JSON数据提取器类( JSONDataExtractor )。
(3) 定义 XML数据提取器类( XMLDataExtractor )。
(4) 添加工厂函数 dataextraction_factory() ,以获得正确的数据提取器类。
(5) 添加处理异常的装饰器函数 extract_data_from() 。
(6) 最终,添加 main() 函数,并使用 Python传统的命令行方式调用该函数。 main 函数的要
点如下。
 尝试从 SQL文件(data/person.sq3)中提取数据,以展示异常处理的方式。
 从 JSON文件中提取数据并解析出结果。
 从 XML文件中提取数据并解析出结果。

测试文件

movies.json

[
 {"title":"After Dark in Central Park",
  "year":1900, 
  "director":null, "cast":null, "genre":null},
 {"title":"Boarding School Girls' Pajama Parade",
  "year":1900, 
  "director":null, "cast":null, "genre":null},
 {"title":"Buffalo Bill's Wild West Parad",
  "year":1900, 
  "director":null, "cast":null, "genre":null},
 {"title":"Caught",
  "year":1900, 
  "director":null, "cast":null, "genre":null},
 {"title":"Clowns Spinning Hats",
  "year":1900, 
  "director":null, "cast":null, "genre":null},
{"title":"Capture of Boer Battery by British",
  "year":1900, 
  "director":"James H. White", "cast":null, "genre":"Short documentary"},
 {"title":"The Enchanted Drawing",
  "year":1900, 
  "director":"J. Stuart Blackton", "cast":null,"genre":null},
 {"title":"Family Troubles",
  "year":1900,
  "director":null, "cast":null, "genre":null},
 {"title":"Feeding Sea Lions",
  "year":1900,
  "director":null, "cast":"Paul Boyton", "genre":null}
 ]

persons.xml 

<persons> 
  <person> 
    <firstName>John</firstName> 
    <lastName>Smith</lastName> 
    <age>25</age> 
    <address> 
      <streetAddress>21 2nd Street</streetAddress> 
      <city>New York</city> 
      <state>NY</state> 
      <postalCode>10021</postalCode> 
    </address> 
    <phoneNumbers> 
      <phoneNumber type="home">212 555-1234</phoneNumber> 
      <phoneNumber type="fax">646 555-4567</phoneNumber> 
    </phoneNumbers> 
    <gender> 
      <type>male</type> 
    </gender> 
  </person> 
  <person> 
    <firstName>Jimy</firstName> 
    <lastName>Liar</lastName> 
    <age>19</age> 
    <address> 
      <streetAddress>18 2nd Street</streetAddress> 
      <city>New York</city> 
      <state>NY</state> 
      <postalCode>10021</postalCode> 
    </address> 
    <phoneNumbers> 
      <phoneNumber type="home">212 555-1234</phoneNumber> 
    </phoneNumbers> 
    <gender> 
      <type>male</type> 
    </gender> 
  </person> 
  <person> 
    <firstName>Patty</firstName> 
    <lastName>Liar</lastName> 
    <age>20</age> 
    <address> 
      <streetAddress>18 2nd Street</streetAddress> 
      <city>New York</city> 
      <state>NY</state> 
      <postalCode>10021</postalCode> 
    </address> 
    <phoneNumbers> 
      <phoneNumber type="home">212 555-1234</phoneNumber> 
      <phoneNumber type="mobile">001 452-8819</phoneNumber> 
    </phoneNumbers> 
    <gender> 
      <type>female</type> 
    </gender> 
  </person> 
</persons> 

chapter01/mycode/factory_method.py

"""
https://zhuanlan.zhihu.com/p/64487092
python的@property是python的一种装饰器,是用来修饰方法的。
创建只读属性
@property装饰器会将方法转换为相同名称的只读属性,可以与所定义的属性配合使用,这样可以防止属性被修改
parsed_data 作为属性
"""

完整代码

def extract_data_from(filepath):
    factory_obj = None
    try:
        factory_obj = dataextraction_factory(filepath)
    except ValueError as e:
        print(e)
    return factory_obj

def main():
    # 异常测试
    sqlite_factory=extract_data_from('../data/person.sq3')
    print()
    #  Cannot extract  data from ../data/person.sq3
    json_factory = extract_data_from('../data/movies.json')
    json_data=json_factory.parsed_data
    print(f"found:{len(json_data)  }  movices")
    for movie in json_data:
        print(f"Title:{movie['title']}")
        year = movie['year']
        if year:
            print(f"Year: {year}")
        director = movie['director']
        if director:
            print(f"Director: {director}")
        genre = movie['genre']
        if genre:
            print(f"Genre: {genre}")
        print()

    """
    xml 解析
    使用工厂方法处理 XML 文件。Xpath 用于寻找所有姓为 Liar 的
    person 元素(使用 liars = xml_data.findall(f".//person[lastName='Liar']") )。
    对于每一个匹配的人,将展示其基本姓名与电话号码信息
    """
    xml_factory = extract_data_from('../data/person.xml')
    xml_data = xml_factory.parsed_data
    liars=xml_data.findall(f".//person[lastName='Liar']")
    print(f'found:{len(liars)} persons')
    for liar in liars:
        firstname = liar.find('firstName').text
        print(f'first name: {firstname}')
        lastname = liar.find('lastName').text
        print(f'last name: {lastname}')
        [print(f"phone number ({p.attrib['type']}):", p.text)
        for p in liar.find('phoneNumbers')]
        print()
if __name__ == '__main__':
    main()

虽然 JSONDataExtractor 和 XMLDataExtractor 有相同的接口,但是它们处理
parsed_data() 返回值的方式并不一致。每个数据解析器必须与不同的 Python代码相配套。

 2.抽象工厂模式

抽象工厂模式是一种一般化的工厂方法模式,它提供了相同的好处:使跟踪对象创建更
容易,将对象的创建与使用解耦,并赋予你提升应用内存使用率与性能的可能性。

如何知道该使用工厂方法还是抽象工厂?

通常从
简单的工厂方法开始。如果发现应用程序需要许多工厂方法,且将这些方法组合起来创建一系列
对象是有意义的,那么就使用抽象工厂

典型的例子是能够在用户使用应用程序时为其更改应用程序的外观(例如,Apple风格界面、Windows风格界面等),而无须终止应用再重新启动。

例子:创建一个游戏

希望至少包括两款游戏:一款儿童游戏,一款成人游戏。我们将根据用户的输入,在运行时决定创建和启动哪款游戏。抽象工厂会负责游戏创建的部分。

游戏: FrogWorld
FrogWorld 适应抽象工厂 ,主要任务是创建游戏注解和障碍物
保持创建方
法的独立性及名称的通用性(例如, make_character() 和 make_obstacle() ),我们将能动
态地更改处于激活状态的工厂(进而改变处于激活状态的游戏),而不需要修改任何代码。在静
态类型语言中,抽象工厂是一个带有空方法的抽象类/接口,但是在 Python 中,这是不必要的,
因为类型是在运行时检查的( j.mp/ginstromdp )。

游戏1:

 FrogWorld。男主角是一只喜欢吃虫子的青蛙。每个
主角都需要一个好的名字,在我们的例子中,这个名字是由用户在运行时给出的。 interact_
with() 方法用于描述青蛙与障碍物(例如,虫子、谜题和其他青蛙)的交互。

"""
游戏: FrogWorld
FrogWorld 适应额抽象工厂 ,主要任务是创建游戏注解和障碍物
保持创建方
法的独立性及名称的通用性(例如, make_character() 和 make_obstacle() ),我们将能动
态地更改处于激活状态的工厂(进而改变处于激活状态的游戏),而不需要修改任何代码。在静
态类型语言中,抽象工厂是一个带有空方法的抽象类/接口,但是在 Python 中,这是不必要的,
因为类型是在运行时检查的( j.mp/ginstromdp )。
"""


class Frog:
    def __init__(self, name):
        self.name = name

    def __str__(self):
        return self.name

    def interact_with(self, obstacle):
        act = obstacle.action()
        msg = f'{self} the Frog encounters {obstacle} and {act}!'
        print(msg)


# 虫子
class Bug:
    def __init__(self):
        pass

    def __str__(self):
        return 'a bug'

    def action(self):
        return 'eats it '


class FrogWorld:
    def __init__(self, name):
        print(self)
        self.player_name = name

    def __str__(self):
        return '\n\n\t------ Frog World -------'

    def make_character(self):
        return Frog(self.player_name)

    def make_obstacle(self):
        return Bug()

游戏2:

名为 WizardWorld 的游戏也是类似的。唯一的区别是,巫师与怪物(如 orks 兽人)战斗,
而不是吃虫子。

FrogWorld 游戏定义Frog 和Bug类

(1) 为FrogWorld 游戏定义Frog 和Bug 类

(2)添加FrogWold 类,在其中使用Frog 和Bug 类

(3)为WizardWold 游戏定义wizrd 和Ork 类

(4) 添加WizardWold 类,在其中使用Wizard 类和Ork 类

(5) 定义GameEnviroment类

(6)添加validate_age() 函数

(7) 使用main()函数 

 获取用户输入的姓名和年龄

根据用户的 年龄决定使用的游戏

实例化正确的游戏类,然后实例化GameEnviroment类

调用enviroment对象的play() 方法 玩游戏

 完整代码

chapter01/mycode/abstract_factory.py

"""
游戏: FrogWorld
FrogWorld 适应额抽象工厂 ,主要任务是创建游戏注解和障碍物
保持创建方
法的独立性及名称的通用性(例如, make_character() 和 make_obstacle() ),我们将能动
态地更改处于激活状态的工厂(进而改变处于激活状态的游戏),而不需要修改任何代码。在静
态类型语言中,抽象工厂是一个带有空方法的抽象类/接口,但是在 Python 中,这是不必要的,
因为类型是在运行时检查的( j.mp/ginstromdp )。
"""


class Frog:
    def __init__(self, name):
        self.name = name

    def __str__(self):
        return self.name

    def interact_with(self, obstacle):
        act = obstacle.action()
        msg = f'{self} the Frog encounters {obstacle} and {act}!'
        print(msg)


# 虫子
class Bug:
    def __init__(self):
        pass

    def __str__(self):
        return 'a bug'

    def action(self):
        return 'eats it '


class FrogWorld:
    def __init__(self, name):
        print(self)
        self.player_name = name

    def __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 = name

    def __str__(self):
        return self.name

    def interact_with(self, obstacle):
        act = obstacle.action()
        msg = f'{self} the Wizard battles against {obstacle}and {act}!'
        print(msg)


# 怪物
class Ork:
    def __str__(self):
        return 'an evil ork'

    def action(self):
        return 'kills it'


class WizardWorld:
    def __init__(self, name):
        print(self)
        self.player_name = name

    def __str__(self):
        return '\n\n\t------ Wizard World -------'

    def make_character(self):
        return Wizard(self.player_name)

    def make_obstacle(self):
        return Ork()


"""
GameEnvironment 类是我们游戏的主入口。它接受一个工厂作为输入,并使用它来创建游
戏世界。 play() 方法初始化主角与障碍物之间的交互

"""


# 游戏的入口 接收一个工厂作为输入,并且使用它创建游戏世界 paly() 方法初始化主角与障碍物之间的交互
class GameEnvironment:
    def __init__(self, facotry):
        self.hero = facotry.make_character()
        self.abstacle = facotry.make_obstacle()

    def play(self):
        self.hero.interact_with(self.abstacle)


def validate_age(name):
    try:
        age = input(f'Welcome {name}. How old are you? ')
        age = int(age)
    except ValueError as err:
        print(f"Age {age} is invalid, please try again...")
        return (False, age)
    return (True, age)


def main():
    name = input("Hello,what's your name?")
    valid_input = False
    while not valid_input:
        valid_input, age = validate_age(name)
        game = FrogWorld if age < 18 else WizardWorld
        environment = GameEnvironment(game(name))
        environment.play()


if __name__ == '__main__':
    main()

运行结果: 

Hello,what's your name?  aa
Welcome   aa. How old are you? 12


	------ Frog World -------
  aa the Frog encounters a bug and eats it !
Hello,what's your name?bb
Welcome bb. How old are you? 19


	------ Wizard World -------
bb the Wizard battles against an evil orkand kills it!

Process finished with exit code 0

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

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

相关文章

【错误解决方案】ModuleNotFoundError: No module named ‘PeptideBuilder‘

1. 错误提示 在python程序中&#xff0c;试图导入一个不存在的模块PeptideBuilder导致的错误&#xff1a; 错误提示&#xff1a;ModuleNotFoundError: No module named PeptideBuilder 2. 解决方案 解决方案是确保你已经正确安装了PeptideBuilder模块。你可以通过pip来安装它…

操作系统章节练习

第5章 存储器管理 一. 多选题&#xff08;共8题&#xff0c;64分&#xff09; 1. (多选题, 8分)为什么在页式存储器中实现程序共享时&#xff0c;必须对共享程序给出相同的页号&#xff1f; A. 共享页号相同方便地址转换。B. 实现程序共享时&#xff0c;由于页式存储结构要求…

多线程---线程池

文章目录 什么是线程池&#xff1f;线程池的实现标准库中的线程池&#xff08;四种&#xff09;自己实现一个线程池 线程池支持的参数在实际的开发中&#xff0c;线程池的线程数如何确定&#xff1f; 什么是线程池&#xff1f; 线程诞生的原因就是进程太“重量”了。虽然线程的…

计算机网络——第一章体系结构相关习题及详细解析

1-1 在OSI参考模型中&#xff0c;自下而上第一个提供端到端服务的层次是&#xff1a; A.数据链路层 B.传输层 C.会话层 D.应用层 答案选择&#xff1a;B.传输层 即&#xff0c;在OSI参考模型中&#xff0c;自下而上第一个提供端到端服务的层次是传输层。…

【数据结构】 队列详解!庖丁解牛般细致讲解!

&#x1f3a5; 屿小夏 &#xff1a; 个人主页 &#x1f525;个人专栏 &#xff1a; 数据结构解析 &#x1f304; 莫道桑榆晚&#xff0c;为霞尚满天&#xff01; 文章目录 &#x1f4d1;前言&#x1f324;️队列的概念剖析☁️什么是队列☁️队列的特性☁️队列的图解 &#x1…

【鸿蒙软件开发】ArkTS容器组件之Badge

文章目录 前言一、Badge组件1.1 子组件1.2 接口接口1参数 接口2参数 BadgePosition枚举说明BadgeStyle对象说明 1.3 示例代码 总结 前言 Badge组件&#xff1a;可以附加在单个组件上用于信息标记的容器组件。 一、Badge组件 可以附加在单个组件上用于信息标记的容器组件。 说…

光强的检测与控制系统设计

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、实习内容二、实习方法2.1 proteus仿真部分2.2 使用Altium designer软件绘制原理图2.2.1 工程创建2.2.2 绘制封装以及链接封装与原件原理图2.2.3检查原件原理…

python不同版本的下载安装和配置

python下载和安装 1 基础软件安装 sudo apt update sudo apt install build-essential zlib1g-dev libncurses5-dev libgdbm-dev libnss3-dev libssl-dev libreadline-dev libffi-dev libsqlite3-dev wget2 python压缩文件下载 我这里下载的是3.9.9,各位也可以根据自己需要下…

精品Python的定制化图书借阅推荐引擎设计与实现

《[含文档PPT源码等]精品基于Python的定制化图书推荐引擎设计与实现》该项目含有源码、文档、PPT、配套开发软件、软件安装教程、项目发布教程、包运行成功&#xff01; 软件开发环境及开发工具&#xff1a; 开发语言&#xff1a;python 使用框架&#xff1a;Django 前端技…

【机器学习】loss损失讨论

大纲 验证集loss上升&#xff0c;准确率也上升&#xff08;即将overfitting&#xff1f;&#xff09;训练集loss一定为要为0吗 Q1. 验证集loss上升&#xff0c;准确率也上升 随着置信度的增加&#xff0c;一小部分点的预测结果是错误的&#xff08;log lik 给出了指数级的惩…

VSCode编写Unity代码自动补全配置

1.下载并安装.NET 7.0&#xff08;C#插件需要&#xff09;和.NET Framework 4.7.1&#xff08;Unity需要&#xff09; .NET 7.0下载链接&#xff1a;https://dotnet.microsoft.com/en-us/download .NET Framework 4.7.1下载链接&#xff1a;https://dotnet.microsoft.com/en-…

Python 日期和时间处理教程:datetime 模块的使用

Python 中的日期不是独立的数据类型&#xff0c;但我们可以导入一个名为 datetime 的模块来使用日期作为日期对象。 示例&#xff1a;导入 datetime 模块并显示当前日期&#xff1a; import datetimex datetime.datetime.now() print(x)日期输出 当我们执行上面示例中的代码…

Java利用Scanner类,从键盘接受一个字符串输入,该字符串包含小写字母,大写字母和数字。分别输出该字符串所包含的大写字母、小写字母和数字的个数。

题目要求&#xff1a;利用Scanner类&#xff0c;从键盘接受一个字符串输入&#xff0c;该字符串包含小写字母&#xff0c;大写字母和数字。分别输出该字符串所包含的大写字母、小写字母和数字的个数。 import java.util.Scanner;public class Demo1 {public static void main(…

算法篇 : 并查集

介绍 英文名&#xff1a;union find set 作用&#xff1a;合并集合&#xff0c;查询集合 合并&#xff1a;将有直接关系的顶点放在一个集合里面 查找&#xff1a;查询某个顶点所属的集合 集合的标志&#xff1a;用祖先点的标号作为每个集合的标识 案例 如果说将下图的集合2合并…

H5游戏源码分享-接苹果游戏拼手速

H5游戏源码分享-接苹果游戏拼手速 看看在20秒内能接多少个苹果 <html> <head><title>我是你的小苹果</title><meta charset"utf-8"/><meta name"viewport" content"initial-scale1, user-scalableno, minimum-scale…

【DevChat】智能编程助手 - 使用评测

写在前面&#xff1a;博主是一只经过实战开发历练后投身培训事业的“小山猪”&#xff0c;昵称取自动画片《狮子王》中的“彭彭”&#xff0c;总是以乐观、积极的心态对待周边的事物。本人的技术路线从Java全栈工程师一路奔向大数据开发、数据挖掘领域&#xff0c;如今终有小成…

【unity小技巧】unity排序问题的探究

文章目录 前言一、排序图层二、sorting Group的使用三、树木排序设计方法一 代码控制方法二 拆分图片方法三 透视排序1. 普通物品排序2. TileMap瓦片排序设计 完结 前言 unity的排序问题其实之前分享的项目多多少少都有提到一点&#xff0c;但是没有单独拿出来说&#xff0c;所…

常用第三方库

Moment GTC(Greenwish Mean Time)&#xff1a;格林威治时间&#xff0c;太阳时&#xff0c;精确到毫秒UTC(Universal Time Coodinated)&#xff1a;世界协调时间&#xff0c;原子种计时&#xff0c;精确到纳秒 GTC和UTC都是以0时区作为标准时间戳&#xff1a;以UTC的1970-1-1 …

天气数据可视化平台-计算机毕业设计vue

天气变幻无常&#xff0c;影响着我们生活的方方面面&#xff0c;应用天气预报信息可以及时了解天气的趋势&#xff0c;给人们的工作、生活等带来便利&#xff0c;也可以为我们为未来的事情做安排和打算&#xff0c;所以一个精准的、易读 通过利用 程序对气象网站大量的气象信息…

H5游戏源码分享-命悬一线

H5游戏源码分享-命悬一线 在合适的时机跳下绳子&#xff0c;能安全站到木桩上&#xff0c;就通过。 游戏源码 <!DOCTYPE html> <html> <head><meta http-equiv"Content-Type" content"text/html; charsetutf-8" /><meta name&…