Skip to content

设计模式之工厂模式

人生若只如初见,何事秋风悲画扇。

Author: 李东阳

1、 什么是工厂模式

在面向对象编程中,术语“工厂”表示一个负责创建其他类型对象的类。通常情况下,作为一个工厂的类有一个对象以及与它关联的多个方法。客户端使用某些参数调用此方法,之后,工厂会据此创建所需类型的对象,然后将它们返回给客户端。

2、 工厂模式的种类

  • 简单工厂模式,用于生成一系列具有相同类型属性的产品。

  • 工厂方法模式,用于生成一系列产品,不同产品可包含不同类型的属性。

  • 抽象工厂模式,用于生成多个相关系列的产品,同一个系列的不同产品也可以包含不同类型的属性。

工厂模式的应用场景:在任何需要生成复杂对象的地方,都可以使用工厂模式。对于简单的,只需要简单的new一个对象即可,无需使用工厂模式。个人觉得工厂模式不是很好。

3、 工厂模式的实现

3.1、简单工厂模式

允许接口创建对象,但不会暴露对象的创建逻辑。工厂可以帮助开发人员创建不同类型的对象,而不是直接将对象实例化。

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()
    my_cat = ff.make_sound('Cat')

3.2、工厂方法模式

工厂方法模式定义了一个接口来创建对象,但具体实例化哪个类则是由它的子类决定的。

举个例子:

​ 假设我们需要在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):
        self.sections = []
        self.createProfile()

    @abstractmethod
    def createProfile(self):
        pass

    def getSections(self):
        return [type(i).__name__ for i in self.sections]  # 返回简介拥有的所有部分的信息

    def addSections(self, section):
        self.sections.append(section)  # 给简介添加各部分

# 创建LinkedIn简介类
class linkedin(Profile):
    def createProfile(self):
        self.addSections(PersonalSection())  # 添加个人部分
        self.addSections(PatentSection())  # 添加专利部分
        self.addSections(PublicationSection())  # 添加出版部分

# 创建Facebook简介类
class facebook(Profile):
    def createProfile(self):
        self.addSections(PersonalSection())  # 添加个人部分
        self.addSections(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 --', profile.getSections())

在上面代码中,我们首先创建了Section抽象类,基于它创建了PersonalSection、AlbumSection、PatentSection和PublicationSection等用于描述简介章节的类。然后又创建了抽象类Profile,基于它创建了linkedin和facebook两个类,用于实例化它们所包含的简介类。

3.3、抽象工厂模式

抽象工厂模式的主要目的是提供一个接口来创建一系列相关对象,而无需指定具体的类。抽象工厂模式确保客户端与对象的创建相互隔离,同时还确保客户端能够使用创建的对象。

举个例子:

​ 假设我们开了一家披萨店,供应印式披萨和美式披萨,其中又各自都包含素食披萨和非素食披萨。

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()]:
            self.factory = factory  # 实例化披萨工厂
            self.NonVegPizza = self.factory.createNonVegPizza()  # 实例化素食披萨
            self.VegPizza = self.factory.createVegPizza()  # 实例化非素食披萨
            self.VegPizza.prepare()  # 准备素食披萨
            self.NonVegPizza.serve(self.VegPizza)  # 将肉/火腿搭配到素食披萨上


if __name__ == '__main__':
    pizza = PizzaStore()  # 实例化披萨商店
    pizza.makePizzas()  # 制作披萨

4、总结

工厂模式的优点

  • 解耦,即对象的创建可以独立于类的实现。

  • 客户端(高层代码)无需了解创建对象的类,但是照样可以使用它来创建对象。它只需要知道需要传递的接口、方法和参数,就能够创建所需类型的对象了。这简化了客户端的实现。

  • 可以轻松地在工厂中添加其他类来创建其他类型类型的对象,而这无需更改客户端代码。最简单的情况下,客户端只需要传递另一个参数就可以了。

工厂模式的缺点

  • 过于繁琐