抽象工厂模式(Abstract Factory Pattern):属于创建型模式,它提供了一种创建对象的最佳方式。在抽象工厂模式中,接口是负责创建一个相关对象的工厂,不需要显式指定它们的类,每个生成的工厂都能按照工厂模式提供对象。
意图: 提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。
主要解决:主要解决接口选择的问题。
何时使用:系统的产品有多于一个的产品族,而系统只消费其中某一族的产品。
如何解决:在一个产品族里面,定义多个产品。
关键代码: 在一个工厂里聚合多个同类产品。
优点:当一个产品族中的多个对象被设计成一起工作时,它能保证客户端始终只使用同一个产品族中的对象。抽象工厂模式相较于工厂模式,划分更加明确清晰,面对复杂的生产任务,管理和生产性能会更加高效。
缺点: 产品族扩展非常困难,要增加一整个系列的某一产品。
产品等级结构 : 产品等级结构即产品的继承结构,如一个抽象类是电视机,其子类有海尔电视机、海信电视机、TCL电视机,则抽象电视机与具体品牌的电视机之间构成了一个产品等级结构,抽象电视机是父类,而具体品牌的电视机是其子类。
产品族 : 在抽象工厂模式中,产品族是指由同一个工厂生产的,位于不同产品等级结构中的一组产品,如海尔电器工厂生产的海尔电视机、海尔电冰箱,海尔电视机位于电视机产品等级结构中,海尔电冰箱位于电冰箱产品等级结构中。
抽象工厂模式包含如下角色
- AbstractFactory:抽象工厂
- ConcreteFactory:具体工厂
- AbstractProduct:抽象产品
- Product:具体产品
时序图:
应用实例: 对于一个生产水果的工厂,工厂模式主要针对一种水果创建一个涵盖与该水果相关所有业务的工厂(例如:葡萄的运输、保存、加工、包装、售卖等相关业务全部被该工厂承包);而抽象工厂模式主要针对生产其中的某一环节进行创建相应的工厂(例如:运输工厂负责管理所有水果的运输,售卖工厂负责管理所有水果的价格和售卖,库存工厂负责管理所有水果的库存计数等)。
实现代码:
class FruitClass:
# 品种工厂
def get_name(self, name_index):
if name_index == 0:
name_object = OrangeClass()
elif name_index == 1:
name_object = Hami_MelonClass()
elif name_index == 2:
name_object = GrapeClass()
else:
name_object = None
return name_object
class OrangeClass:
# 橘子类
def __init__(self):
self.name = "橘子"
def print_name(self):
print("您购买的水果为:%s" % self.name)
class Hami_MelonClass:
# 哈密瓜类
def __init__(self):
self.name = "哈密瓜"
def print_name(self):
print("您购买的水果为:%s" % self.name)
class GrapeClass:
# 葡萄类
def __init__(self):
self.name = "葡萄"
def print_name(self):
print("您购买的水果为:%s" % self.name)
class FruitWeight:
# 称重工厂
def __init__(self, weight):
self.weight = float(weight)
def print_weight(self):
print("该水果的重量为:%.2f千克" % self.weight)
class FruitPrice:
# 价格工厂
def get_price(self, name_index, variety):
if name_index == 0:
price_object = OrangePrice(variety)
elif name_index == 1:
price_object = Hami_MelonPrice()
elif name_index == 2:
price_object = GrapePrice()
else:
price_object = None
return price_object
class OrangePrice:
# 橘子价格类
def __init__(self, variety):
self.variety = variety
if self.variety == 1:
self.price = 8.5
else:
self.price = 11.0
def print_price(self):
print("该水果的单价为:%.2f元/千克" % self.price)
class Hami_MelonPrice:
# 哈密瓜价格类
def __init__(self):
self.price = 24.3
def print_price(self):
print("该水果的价格为:%.2f元/千克" % self.price)
class GrapePrice:
# 葡萄价格类
def __init__(self):
self.price = 16.2
def print_price(self):
print("该水果的价格为:%.2f元/千克" % self.price)
return self.price
class FruitPack:
# 包装工厂
def __init__(self, pack):
if pack == 1:
self.pack = "散称"
else:
self.pack = "盒装"
def print_pack(self):
print("该水果的打包方式为:%s" % self.pack)
class FruitFactory:
def __init__(self, name_index, weight, variety, pack):
# 任务的分配,品种、重量、价格、包装方式
self.name_object = FruitClass().get_name(name_index)
self.weight_object = FruitWeight(weight)
self.price_object = FruitPrice().get_price(name_index, variety)
self.pack_object = FruitPack(pack)
def print_purchase(self):
# 计算购买的金额
money = self.price_object.price * self.weight_object.weight
print("需要支付的金额共计为:%.2f元" % money)
def show_info(self):
# 展示最终的购买信息
self.name_object.print_name()
self.weight_object.print_weight()
self.price_object.print_price()
self.pack_object.print_pack()
self.print_purchase()
print("-*-" * 20)
class Consumer:
# 消费者类
def __init__(self):
print("-*-" * 20)
# 输入原始的“购买需求”信息
self.name = input("请输入你要购买的水果名称:0.橘子 1.哈密瓜 2.葡萄\n")
self.weight = input("请输入你要购买水果的重量(kg):\n")
self.variety = input("如果您购买橘子,我们有2种橘子:0.不买橘子 1.甘橘 2.砂糖橘\n")
self.pack = input("请您选择该水果的包装方式:1.散称 2.盒装\n")
print("-*-" * 20)
def request(self):
# 返回相关的购买信息
return self.name, self.weight, self.variety, self.pack
if __name__ == '__main__':
# 创建顾客
buyer = Consumer()
# 拿到顾客的购买信息
buy_info = buyer.request()
# 使用水果工厂,传达指令至旗下的子工厂并执行购买操作
buy_res = FruitFactory(int(buy_info[0]), int(buy_info[1]), int(buy_info[2]), int(buy_info[3]))
# 购买信息的展示
buy_res.show_info()
抽象工厂用在车辆织造中。相同的机械装置用来冲压不同的车辆模型的部件(门,面板,车身罩体,挡泥板,以及各种镜子)。聚合了不同机械装置的模型是可配置的,而且在任何时候都可以轻松变更。车辆制造的抽象工厂的例子如下:
import random
class PetShop:
"""A pet shop"""
def __init__(self, animal_factory=None):
"""pet_factory is our abstract factory. We can set it at will."""
self.pet_factory = animal_factory
def show_pet(self):
"""Creates and shows a pet using the abstract factory"""
pet = self.pet_factory.get_pet()
print("We have a lovely {}".format(pet))
print("It says {}".format(pet.speak()))
print("We also have {}".format(self.pet_factory.get_food()))
# Stuff that our factory makes
class Dog:
def speak(self):
return "woof"
def __str__(self):
return "Dog"
class Cat:
def speak(self):
return "meow"
def __str__(self):
return "Cat"
# Factory classes
class DogFactory:
def get_pet(self):
return Dog()
def get_food(self):
return "dog food"
class CatFactory:
def get_pet(self):
return Cat()
def get_food(self):
return "cat food"
# Create the proper family
def get_factory():
"""Let's be dynamic!"""
return random.choice([DogFactory, CatFactory])()
# Show pets with various factories
for i in range(3):
shop = PetShop(get_factory())
shop.show_pet()
print("=" * 20)
### OUTPUT ###
# We have a lovely Dog
# It says woof
# We also have dog food
# ====================
# We have a lovely Dog
# It says woof
# We also have dog food
# ====================
# We have a lovely Cat
# It says meow
# We also have cat food
# ====================
工厂方法和抽象工厂区别
一开始时使用工厂方法,因为它更简单。如果后来发现应用需要许多工厂方法,那么将创建一系列对象的过程合并在一起更合理,从而最终引入抽象工厂。
抽象工厂有一个优点,在使用工厂方法时从用户视角通常是看不到的,那就是抽象工厂能够通过改变激活的工厂方法动态地(运行时)改变应用行为。一个经典例子是能够让用户在使用应用时改变应用的观感(比如,Apple风格和Windows风格等),而不需要终止应用然后重新启动。
实现:在应用中包含一个迷你游戏让用户娱乐娱乐。我们希望至少包含两个游戏, 一个面向孩子,一个面向成人。在运行时,基于用户输入,决定该创建哪个游戏并运行。游戏的创建部分由一个抽象工厂维护。
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'
# FrogWorld类是一个抽象工厂。它的主要责任是游戏的主角和障碍物。保持创建方法的独立和方法名称的普通(例如,make_character(),
# make_obstacle())让我们可以动态的改变活动工厂(以及活动的游戏)而不设计任何的代码变更。
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()
# GameEnviroment是我们游戏的主要入口。它接受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)
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 = GameEnvironment(game(name))
environment.play()
main()
# Hello. What's your name? Nick
# Welcome Nick. How old are you? 17
# ------ Frog World -------
# Nick the Frog encounters a bug and eats it!
使用场景
在很多软件系统中需要更换界面主题,要求界面中的按钮、文本框、背景色等一起发生改变时,可以使用抽象工厂模式进行设计。
抽象工厂模式与工厂方法模式的区别
工厂方法模式:
1.一个抽象产品类,可以派生出多个具体产品类
2.一个抽象工厂类,可以派生出多个具体工厂类
3.每个具体工厂类,只能创建一个具体产品的实例
抽象设计模式:
1.多个抽象产品类,可以派生出多个具体产品类
2.一个抽象工厂类,可以派生出多个具体工厂类
3.每个具体工厂类,可以创建多个具体类的实例
简单工厂模式是客户端用不同的参数通过工厂获取不同的产品实例。
工厂方法模式是客户端通过工厂的不同实例获取不同的产品实例。
抽象工厂模式是工厂可以生成不同的产品实例,客户端通过不同实例获取不同的产品。
总结
其根本思想就是将产品归类分组,然后将好几组产品构成一族。每个工厂负责生产一族产品,而工厂中的每个方法负责生产一种类型的产品。