一、工厂方法
(一)工厂模式运用场景
-
如果因为应用创建对象的代码分布在多个不同的地方,而不是仅在一个函数/方法中,你发 现没法跟踪这些对象,那么应该考虑使用工厂方法模式。
- 有一个工厂方法负责连接到不同的数据库(MySQL、SQLite)。
- 另一个工厂方法负责创建要求的 几何对象(圆形、三角形)。
- 若需要将对象的创建和使用解耦,工厂方法也能派上用场。
- 工厂方法可以在必要时创建新的对象,从而提高性能和内存使用率。
(二)工厂模式案例
import xml.etree.ElementTree as etree
import json
class JSONConnector:
def __init__(self, filepath):
self.data = dict()
with open(filepath, mode='r') 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
if __name__ == '__main__':
# 要那个传哪个,不占用内存
sqlite_factory = connect_to('person.sq3')
xml_factory = connect_to('person.xml')
json_factory = connect_to('person.json')
二、抽象工厂
(一)什么事抽象工厂
一个抽象工厂是(逻辑上的)一组工厂方法,其中的每个工厂方法负责产生不同种类的对象。
(二)应用场景
- 程序包django_factory是一个用于在测试中创建Django模型的抽象工厂实现,可用来为支持测试专有属性的模型创建实例。这能让测试代码的可读性更高,且能避免共享不必要的代码,故有其存在的价值。
- 通常一开始时使用工厂方法,因为它更简单。如果后来发现应用需要许多工厂方法,那么将创建一系列对象的过程合并在一起更合理,从而最终引入抽象工厂。
- 抽象工厂能够通过改变激活的工厂方法动态地(运行时)改变应用行为。
(三)应用案例
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 '\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):
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 '\n\n\t------ Wizard World -------'
def make_character(self):
return Wizard(self.player_name)
def make_obstacle(self):
return Ork()
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)
def validate_age(name):
try:
age = raw_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 = raw_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()