细说Python设计模式之工厂模式

关于工厂模式

在上一篇文章中,我们讲到的是单例模式,单例一种创建型设计模式。这篇我们讲解另一种创建型模式,工厂模式。

工厂模式具有以下优点:

  1. 松耦合,即对象的创建可以独立于类的实现。
  2. 客户端无需了解创建对象的类,它只需要知道需要传递的接口、方法和函数,就能够创建所需类型的对象了,这简化了客户端的实现。
  3. 可以轻松在工厂中添加其他类来创建其他类型的对象,这无需更改客户端代码。最简单的情况下,客户端只需要传递另一个参数即可。
  4. 工厂还可以重用现有对象,但是,如果客户端直接创建对象的话,总是创建一个新对象。

**举例说:**假如一家公司是生成手机的,公司里的一台机器目前正在生产某为的手机CPU,现在公司CEO认为现在需要根据市场生产具有5g功能的cpu,这时工厂模式就派上用场了。在这种情况下,机器成为了接口,CEO是客户端。CEO只需要关心制造的对象(5gcpu)和创建对象的接口(机器)。

Factory(工厂)模式有三种变体。如下:

  1. 简单工厂模式:允许接口创建对象,但不会暴露对象的创建逻辑 。
  2. 工厂方法模式:允许接口创建对象,但是使用哪个类来创建对象,这是交由子类来决定。
  3. 抽象工厂模式:抽象工厂是一个能够创建一系列相关的对象而无需指定/公开其具体类的接口。该模式能够提供其他工厂的对象,在其内部创建其他对象。
细说工厂模式:
简单工厂模式:

简单工厂模式:简单工厂本身不是一种模式。在开发人员进一步了解前,需要详细了解一下工厂方法和抽象工厂方法。工厂可以帮助开发人员创建不同类型的对象,而不是直接将对象实例化。

1号图
UML图解:这里客户端类使用的是Factory类,该类具有create_type()方法。当客户端使用类型参数调用create_type()方法,Factory会根据传入的参数,返回Product1或Product2.

下面代码有助于我们进一步理解简单工厂模式。我们先创建一个名为Animal的抽象产品。Animal是一个抽象的基类(ABCMeta是Python的特殊元类,用来生成类Abstract),它带有方法do_say()。我们利用Animal接口创建了两种产品(Cat和Dog),并实现了do_say()方法来提供这些动物的相应叫声。ForestFactory是一个带有make_sound()方法的工厂。根据客户端传递的参数类型,它就可以在运行时创建适当的
Animal实例,并输出正确的声音。

例:

from abc import ABCMeta, abstractmethod


class Animal(metaclass=ABCMeta):
    @abstractmethod
    def do_say(self):
        pass


class Dog(Animal):
    def do_say(self):
        print('旺旺!!!')


class Cat(Animal):
    def do_say(self):
        print('喵喵!!!')


# forest Factory defined

class ForestFactory(object):
    def make_sound(self, obj_type):
        return eval(obj_type)().do_say()



# Client code

if __name__ == '__main__':
    a = ForestFactory()
    animal = input('请输入Cat或Dog:')
    a.make_sound(animal)

输出:
在这里插入图片描述

工厂方法模式

1. 了解工厂方法模式:

  1. 我们定义了一个接口来创建对象,但是工厂本身不负责创建对象,而是将这一任务交由子类来完成,即子类决定了要实例化哪些类。
  2. Factory方法的创建是通过继承而不是通过实例化来完成的。
  3. 工厂方法使设计更具加具有可制定性。它可以返回相同的实例或子类,而不是某种类型的对象(就像在简单工厂方法中的那样。)。

在这里插入图片描述

在UML图中, 有一个包含factoryMethod()方法的抽象类 Creator.FactoryMethod()方法负责创建指定类型的对象ConcreteCreator 类提供了一个实现Creator抽象类的factoryMethod()方法,这种方法可以在运行时修改已创建的对象。ConcreteCreator创建ConcreteProduct,并确保其创建的对象实现了Product类,同时为Product接口中的所有方法提供相应的实现。

简而言之,Creator接口的factoryMethod()方法和ConcreteCreator类共同决定了要创建Product的哪个子类。因此,工厂方法模式定义了一个接口来创建对象,但具体实例化哪个类则是由它的子类决定的。

2. 实现工厂方法
现在让我们来看看具体是怎么实现的,在下面的代码中,首先定义接口Product。我们将创建一个Section抽象类来定义一个区是哪个方面内容的,让它尽量保持简单,同时还提供一个抽象方法describle().
然后我们会创建多个ConcreteProduct、PersonalSection、AlbumSection、PatentSection、PublicactionSection类。这些类实现describe()抽象方法并打印它们各自的区名称。

我们创建一个名为Profile的抽象类Creator。Proflie[Creator]抽象类提供了一个工厂方法,即createProfile()。createProfile()方法应该由ConcreteClass实现,来实际创建带有适当区的简介。Profile抽象类不知道每个简介应具有哪些区。例如,Facebook的简介应该提供个人信息区和相册区。所以我们将让子类来决定这些。

我们创建了两个ConcreteCreator类,即linkedin和facebook。每个类都实现createProfile()抽象方法,由该方法在运行时实际创建(实例化)多个区(ConcreteProducts):
例:

from abc import ABCMeta, abstractmethod


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 PublicactionSection(Section):
    def describe(self):
        print('Publicaction Section')


class Profile(metaclass=ABCMeta):
    def __init__(self):
        self.sections = []
        self.createProfile()

    @abstractmethod
    def createProfile(self):
        pass

    def getSections(self):
        return self.sections

    def addSections(self, section):
        self.sections.append(section)


class linkedin(Profile):
    def createProfile(self):
        self.addSections(PersonalSection())
        self.addSections(PatentSection())
        self.addSections(PublicactionSection())


class facebook(Profile):
    def createProfile(self):
        self.addSections(PersonalSection())
        self.addSections(AlbumSection)


"""
最后,开始编写决定实例化哪个Creator类的客户端代码,以便让它根据指定的选项创建所需的简介。
"""
if __name__ == '__main__':
    profile_type = input('你想创建哪个简介:【LinkedIn or Facebook】')
    profile = eval(profile_type.lower())()
    print("创建配置文件.....", type(profile).__name__)
    print('简介部分有---', profile.getSections())

输出结果:
在这里插入图片描述
运行完整的代码,它会首先要求输入要去创建的简介名称,我们以输入FaceBook为例,他实例化facebook[ConcreateCreator]类。它会在内部创建ConcreteProduct,也就是说,将实例化PersonalSection和AlbumSection。

工厂模式优点:

  1. 它具有更大的灵活性,使代码更加通用,因为它不是单纯地实例化某个类。这样,实现哪些类取决于接口(Product),而不是ConcreteProduct类。
  2. 它们是松耦合的,因为创建对象的代码与使用它的代码是分开的。客户端完全不需要关心传递哪些参数以及需要实例化哪些类。由于添加新类更加容易,所以降低了维护成本。
细说抽象工厂模式:

抽象工厂模式主要目的是提供一个接口来创建一系列相关对象。而无需指定具体的类。工厂方法将创建实例的任务委托给子类,而抽象工厂方法的目标是创建一系列相关目标对象。
如图:ConcreteFactory1和ConcreteFactory2是通过AbstractFactory接口创建的此接口具有创建多种产品的相应方法。

在这里插入图片描述
ConcreteFactory1和ConcreteFactory2实现了AbstractFactory,并创建实例ConcreteProduct1、ConcreteProduct2、AnotherConcreteProduct1和AnotherConcreteProduct2。
在这里,ConcreteProduct1和ConcreteProduct2是通过AbstractProduct接口创建的,而AnotherConcreteProduct1和AnotherConcreteProduct2则是通过AnotherAbstractProduct接口创建的。
实际上,抽象工厂模式不仅确保客户端与对象的创建相互隔离,同时还确保客户端能够使用创建的对象。但是,客户端只能通过接口访问对象。如果要使用一个系列中的多个产品,那么抽象工厂模式能够帮助客户端一次使用来自一个产品/系列的多个对象。例如,如果正在开发的应用应该是平台无关的,则它需要对各种依赖项进行抽象处理,这些依赖项包括操作系统、文件系统调用,等等。抽象工厂模式负责为整个平台创建所需的服务,这样的话,客户端就不必直接创建平台对象。

我们开办了一家披萨店,供应美味的印式和美式披萨饼。为此,我们首先创建一个抽象基类——PizzaFactory(AbstractFactory见前面的UML图)。PizzaFactory类有两个抽象方法即createVegPizza()和createNonVegPizza(),它们需要通过ConcreteFactory实现。在这个例子中,我们创造了两个具体的工厂,分别名为IndianPizzaFactory和USPizzaFactory。下面让我们看看这两个具体工厂的实现代码:

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()

现在,让我们进一步定义AbstractProducts。在下面的代码中,我们将创建两个抽象类:VegPizza和NonVegPizza(AbstractProduct和AnotherAbstract Product见前面的UML图)。它们都定义了自己的方法,分别是prepare()和serve()。
然后我们为每个AbstractProducts定义ConcreteProducts。现在,就这里而言,我们将创建DeluxVeggiePizza和MexicanVegPizza,并实现prepare()方法。ConcreteProducts1和ConcreteProducts2将代表UML图中的这些类。

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__)

当用户点餐时,要了一份美式非素食披萨的时候,USPizzaFactory负责准备素食,然后再加上火腿,即可完成。

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)


pizza = PizzaStore()
pizza.makePizzas()

输出如图:
在这里插入图片描述

比较工厂方法和抽象工厂方法
工厂方法抽象工厂方法
它向客户端开放了一个创建对象的方法抽象工厂方法包含一个或多个工厂方法来创建一个系列的相关对象
它使用继承和子类决定要创建哪个对象它使用组合将创建对象的任务委托给其他类
工厂方法用于创建一个产品抽象方法用于创建相关产品的系列

在本文,我们介绍了工厂设计模式及其使用的上下文。
我们还考察了简单工厂,它可以在运行时根据客户端的传入参数类型来创建相应的实例。

另外我们还学习了工厂方法模式,它是简单工厂的一个变体。在这种模式中,我们定义了一个接口来创建对象,但是对象的创建却是交由子类来完成。

最后我们学习了抽象工厂方法,它提供了一个接口,无需指定具体的类就能创建一系列的相关对象。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值