工厂模式
源码下载地址:https://github.com/myt2000/design_patterns/tree/master/chapter1
其实一直搞不明白的重要性,最近看了一下,确实在一定程度可以提高代码复用性,下面介绍工厂模式。
在工厂模式设计中,客户端(调用方)可以请求一个对象,而无需知道这个对象来自哪里;也就是,使用哪个类来生成这个对象。工厂背后的思想是简化对象的创建。与客户端(调用方)自己基于类实例化直接创建对象相比,基于一个中心化函数来实现,更易于追踪创建了哪些对象。通过将创建对象的代码和使用对象的代码解耦,工厂能降低应用维护的复杂度。
工厂通常有两种形式:
- 工厂方法,它是一个方法(或以地道的python术语来说,是一个函数),对不同的输入参数返回不同的结果;
- 抽象工厂,它是一组用于创建一系列相关事务对象的工厂方法
1. 简单的应用案例
class A(object):
pass
if __name__ == '__main__':
a = A()
b = A()
print(id(a) == id(b))
print(a, b)
'''
False
<__main__.A object at 0x0000025432EF7548> <__main__.A object at 0x00000254356A11C8>
'''
可以观察出每次创建的实例的对象内存地址是不一样的
2.工厂方法
factory_method
读取某个文件(xml或者json文件),并解析数据,其他文件格式按异常处理
主要使用了xml.etree.ElementTree
中的parse
,find
,findall
,attrib
等方法
输出打印的时候主要用了 [print('phone number ({})'.format(p.attrib['type']), p.text) for p in liar.find('phoneNumbers')]
列表表达式的方式,减少了for循环的使用
该案例主要是针对json和xml格式的文件作为参数输入
分别定义JSONConnector和XMLConnector对文件处理的类,文件作为参数传入后,函数connection_factory
判断一下使用哪个类
import xml.etree.ElementTree as etree
import json
class JSONConnector:
def __init__(self, filepath):
self.data = dict()
with open(filepath, mode="r", encoding='utf-8') as f:
self.data = json.load(f)
@property
def parsed_data(self):
return self.data
class XMLConnector:
def __init__(self, filepath):
self.tree = etree.parse(filepath)
@property
def parsed_data(self):
return self.tree
def connection_factory(filepath):
if filepath.endswith('json'):
connector = JSONConnector
elif filepath.endswith('xml'):
connector = XMLConnector
else:
raise ValueError('Cannot connect to {}'.format(filepath))
return connector(filepath)
def connect_to(filepath):
factory = None
try:
factory = connection_factory(filepath)
except ValueError as ve:
print(ve)
return factory
def main():
sqlite_factory = connect_to('data/person.sq3')
print()
xml_factory = connect_to('data/person.xml')
xml_data = xml_factory.parsed_data
liars = xml_data.findall(".//{}[{}='{}']".format('person',
'lastName', 'Liar'))
print('found:{} persons'.format(len(liars)))
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.attrib['type']),
p.text) for p in liar.find('phoneNumbers')]
print()
json_factory = connect_to('data/donut.json')
json_data = json_factory.parsed_data
print('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()
3.抽象工厂
根据年龄判断是否小于18岁,进入不同的实例类FrogWorld
、WizardWorld
GameEnvironment
初始化时根据传入的类,进入不同的类实例化,最终返回结果
调用过程
class Frog:
def __init__(self, name):
self.name = name
def __str__(self):
return self.name
def 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'
class FrogWorld:
def __init__(self, name):
print(self)
self.player_name = name
def __str__(self):
return '
- - - - - - 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):
print('{} the Wizard battles against {} and {}!'.format(self, obstacle, obstacle.action()))
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 '
- - - - - - Wizard World ----'
def make_character(self):
return Wizard(self.player_name)
def make_obstacle(self):
return Ork()
class GameEnviroment:
def __init__(self, factory):
self.hero = factory.make_character()
self.obstacle = factory.make_obstacle()
def play(self):
self.hero.interact_with(self.obstacle)
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 = False
while not valid_input:
valid_input, age = validate_age(name)
game = FrogWorld if age < 18 else WizardWorld
environment = GameEnviroment(game(name))
environment.play()
if __name__ == '__main__':
main()
结果:
//大于等于18岁的结果
Hello. What's your name? qwer
Welcome qwer. How old are you? 56
- - - - - - Wizard World ----
qwer the Wizard battles against an evil ork and kills it!
//小于18岁的结果
Hello. What's your name? henry
Welcome henry. How old are you? 12
- - - - - - Frog World ----
henry the Frog encounters a bug and eats it!