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