概述
在面向对象编程中,术语“工厂”表示一个负责创建其他类型对象的类。通常情况下,作为一个工厂的类有一个对象以及与它关联的多个方法。客户端使用某些参数调用此方法,之后,工厂会据此创建所需类型的对象,然后将它们返回给客户端。
工厂模式有3种变体:
(1)简单工厂模式,用于生成一系列具有相同类型属性的产品。
(2)工厂方法模式,用于生成一系列产品,不同产品可包含不同类型的属性。
(3)抽象工厂模式,用于生成多个相关系列的产品,同一个系列的不同产品也可以包含不同类型的属性。
工厂模式的应用场景:在任何需要生成复杂对象的地方,都可以使用工厂模式。对于简单的,只需要简单的new一个对象即可,无需使用工厂模式。如果简单对象使用工厂模式,需要引入一个工厂类,增加系统的复杂度。
实战
一、简单工厂模式
允许接口创建对象,但不会暴露对象的创建逻辑。工厂可以帮助开发人员创建不同类型的对象,而不是直接将对象实例化。
from abc import ABCMeta, abstractmethod
# 创建Animal抽象类
class Animal(metaclass=ABCMeta):
@abstractmethod
def do_say(self):
pass
# 创建Dog类
class Dog(Animal):
def do_say(self):
print('Bhow Bhow!')
# 创建Cat类
class Cat(Animal):
def do_say(self):
print('Meow Meow!')
# 创建工厂类
class ForestFactory:
def make_sound(self, object_type):
return eval(object_type)().do_say()
if __name__ == '__main__':
ff = ForestFactory()
ff.make_sound('Cat')
ABCMeta是python的特殊元类,用来生成类Abstract,@abstractmethod为抽象方法,含@abstractmethod的类不能被实例化,继承了含@abstractmethod方法的子类必须复写所有@abstractmethod装饰的方法。
上面代码中,Animal是一个抽象的基类,它带有方法do_say()。我们利用Animal接口创建了两种产品(Cat和Dog),并实现了do_say()方法来提供这些动物相应的叫声。
ForestFactory是一个带有make_sound()方法的工厂。根据客户端传递的参数类型,它就可以在输出正确的声音。
二、工厂方法模式
工厂方法模式定义了一个接口来创建对象,但具体实例化哪个类则是由它的子类决定的。
假设我们需要在LinkedIn、Facebook为个人或公司建立简介。那么,每个简介都有某些特定的组成章节。在LinkedIn的简介中,包含个人信息、申请的专利和出版的作品。在Facebook的简介中,包含个人信息、相册。
from abc import ABCMeta, abstractmethod
# 创建Section抽象类
class Section(metaclass=ABCMeta):
@abstractmethod
def describe(self):
pass
# 创建个人信息部分类
class PersonalSection(Section):
def describe(self):
print('Personal Section')
# 创建相册部分类
class AlbumSection(Section):
def describe(self):
print('Album Section')
# 创建专利部分类
class PatentSection(Section):
def describe(self):
print('Patent Section')
# 创建出版作品部分类
class PublicationSection(Section):
def describe(self):
print('Publication Section')
# 创建Profile抽象类
class Profile(metaclass=ABCMeta):
def __init__(self):
= []
()
@abstractmethod
def createProfile(self):
pass
def getSections(self):
return [type(i).__name__ for i in ] # 返回简介拥有的所有部分的信息
def addSections(self, section):
(section) # 给简介添加各部分
# 创建LinkedIn简介类
class linkedin(Profile):
def createProfile(self):
(PersonalSection()) # 添加个人部分
(PatentSection()) # 添加专利部分
(PublicationSection()) # 添加出版部分
# 创建Facebook简介类
class facebook(Profile):
def createProfile(self):
(PersonalSection()) # 添加个人部分
(AlbumSection()) # 添加相册部分
if __name__ == '__main__':
profile_type = input("Which Profile you'd like to create?[LinkedIn or FaceBook]")
profile = eval(profile_type.lower())()
print('Create Profile...', type(profile).__name__)
print('Profile has sections --', ())
在上面代码中,我们首先创建了Section抽象类,基于它创建了PersonalSection、AlbumSection、PatentSection和PublicationSection等用于描述简介章节的类。然后又创建了抽象类Profile,基于它创建了linkedin和facebook两个类,用于实例化它们所包含的简介类。
三、抽象工厂模式
抽象工厂模式的主要目的是提供一个接口来创建一系列相关对象,而无需指定具体的类。抽象工厂模式确保客户端与对象的创建相互隔离,同时还确保客户端能够使用创建的对象。
假设我们开了一家披萨店,供应印式披萨和美式披萨,其中又各自都包含素食披萨和非素食披萨。
from abc import ABCMeta, abstractmethod
# 创建披萨工厂抽象类
class PizzaFactory(metaclass=ABCMeta):
@abstractmethod
def createVegPizza(self):
pass
@abstractmethod
def createNonVegPizza(self):
pass
# 创建印式披萨工厂类
class IndianPizzaFactory(PizzaFactory):
def createVegPizza(self):
return DeluxVeggiePizza()
def createNonVegPizza(self):
return ChickenPizza()
# 创建美式披萨类
class USPizzaFactory(PizzaFactory):
def createVegPizza(self):
return MexicanVegPizza()
def createNonVegPizza(self):
return HamPizza()
# 创建素食披萨抽象类
class VegPizza(metaclass=ABCMeta):
@abstractmethod
def prepare(self, VegPizza):
pass
# 创建非素食披萨抽象类
class NonVegPizza(metaclass=ABCMeta):
@abstractmethod
def serve(self, VegPizza):
pass
# 创建美味蔬菜披萨类,准备美味蔬菜披萨
class DeluxVeggiePizza(VegPizza):
def prepare(self):
print('Prepare ', type(self).__name__)
# 创建鸡肉披萨类,将素食披萨搭配上鸡肉
class ChickenPizza(NonVegPizza):
def serve(self, VegPizza):
print(type(self).__name__, " is served with Chicken on ", type(VegPizza).__name__)
# 创建墨西哥蔬菜披萨类
class MexicanVegPizza(VegPizza):
def prepare(self):
print('Prepare ', type(self).__name__)
# 创建火腿披萨类,将素食披萨搭配上火腿
class HamPizza(NonVegPizza):
def serve(self, VegPizza):
print(type(self).__name__, " is served with Ham on ", type(VegPizza).__name__)
# 创建披萨商店类
class PizzaStore:
def __init__(self):
pass
def makePizzas(self):
for factory in [IndianPizzaFactory(), USPizzaFactory()]:
= factory # 实例化披萨工厂
= () # 实例化素食披萨
= () # 实例化非素食披萨
() # 准备素食披萨
() # 将肉/火腿搭配到素食披萨上
if __name__ == '__main__':
pizza = PizzaStore() # 实例化披萨商店
() # 制作披萨
总结
工厂模式的优点
1)松耦合,即对象的创建可以独立于类的实现。
2)客户端无需了解创建对象的类,但是照样可以使用它来创建对象。它只需要知道需要传递的接口、方法和参数,就能够创建所需类型的对象了。这简化了客户端的实现。
3)可以轻松地在工厂中添加其他类来创建其他类型类型的对象,而这无需更改客户端代码。最简单的情况下,客户端只需要传递另一个参数就可以了。
4)工厂还可以重用现有对象。但是,如果客户端直接创建对象的话,总是创建一个新对象。
三种模式对比
1)简单工厂模式:允许接口创建对象,但不会暴露对象的创建逻辑。
2)工厂方法模式:允许接口创建对象,但使用哪个类来创建对象,则是交由子类决定的。
3)抽象工厂模式:抽象工厂是一个能够创建一系列相关的对象而无需指定/公开其具体类的接口。该模式能够提供其他工厂的对象,在其内部创建其他对象。