设计模式之工厂方法

工厂模式可以说是最常用的设计模式. 我们分几个主题介绍:

1、简单工厂设计模式.

2、工厂方法与抽象工厂方法的讨论与差异.

3、用Python模拟工厂方法.

4、工厂模式的优缺点。

01 工厂模式

" 工厂"表示一个负责创建其他类型对象的类. 工厂的类有一个对象及与它关联的多个方法. 客户端使用某些参数调用该方法, 之后工厂会根据此创建所需类型的对象, 然后返回给客户端.

工厂具有几个优点:

1、松耦合, 对象的创建可以独立于类的实现.

2、客户端无需了解创建对象的类, 但照样可以使用它来创建对象. 只需要知道需要传递的接口, 方法, 参数, 就可以创建所需类型的对象了.

3、可以轻松在工厂中添加其他类来创建其他类型对象, 而无需更改客户端代码. 简单情况下, 客户端只需要传递另一个参数即可.

4、工厂可以重用现有对象. 但是, 若客户端直接创建对象的话, 总是创建一个新对象.

工厂模式的三个变体:

1、简单工厂模式: 允许接口创建对象, 但不会暴露对象的创建逻辑.

2、工厂方法模式: 允许接口创建对象, 但使用哪个类来创建对象, 则交由子类决定的.

3、抽象工厂模式: 是一个能够创建一系列相关的对象而无需指定其具体类的接口. 该模式能够提供其他工厂对象, 在其内部创建其他对象.

02 简单工厂模式

简单工厂模式就是当我们使用类型参数调用类中的方法时, 该类会根据传入的参数来返回我们想要的值. 我们通过一个例子来了解简单工厂模式.

# coding=utf-8


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("我是喵星人!!!")


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


if __name__ == "__main__":
    ff = ForestFactory()
    animal = input("想听狗说话输入Dog, 猫说话输入Cat: ")
    ff.make_sound(animal)

说明:

ABCMeta是Python特殊的元类, 用来生成类Abstract. 上面代码定义了一个Animal元类, 类中有方法do_say, 类Dog, Cat, 继承了Animal元类,重写了do_say方法. ForestFactory就是一个简单工厂类, make_sound方法根据所传入的对象Dog或者Cat来调用do_say方法返回指定结果. 这个就是简单工厂模式.

03 工厂方法模式

通过下面几点可以帮助我们了解工厂方法模式:

1、定义了一个接口来创建对象, 但是工厂本身并不负责创建对象(上面的简单工厂需要创建对象的), 而是将这一任务交由子类完成, 子类决定了要实例化哪些类.

2、工厂方法的创建是通过继承而不是通过实例化来完成的.

3、工厂方法使设计更加具有可定制性. 可以返回相同的实例或子类, 而不是某种类型的对象. 下面看代码:

# coding=utf-8


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 PublicationSection(Section):
    def describe(self):
        print("Publication 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(PublicationSection())


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


if __name__ == "__main__":
    profile_type = input("你喜欢创建LinkedIn 还是 FaceBook? ")
    profile = eval(profile_type.lower())()
    print("Creating Profile..", type(profile).__name__)
    print("Profile has sections --", profile.getSections())

解释下@abstractmethod装饰器, 经过官网查看有一段重点: A class that has a metaclass derived from ABCMeta cannot be instantiated unless all of its abstract methods and properties are overridden. 要是有英语长难句分析能力这句看懂不难, 大致意思是:

abstractmethod是一个从ABCMeta继承的元类不能实例化, 除非后面继承的 类重新写此方法. 好了开始解释上面的工厂方法代码:

1、首先定义一个总类Section, 里面有个@abstractmethod修饰的方法describe这个就称为工厂模式, 需要后面重写此方法.

2、后面PersonalSection, AlbumSection, PatentSection, PublicationSection四个类都是继承Section, 并且重写了describe方法.

3、同理下面Profile也有一个工厂方法createProfile, Profile的子类linkedin和facebook重写.

4、以后只需要修改子类中的createProfile方法就可以添加修改Section.不需要修改父类.

5、说白了就是在父类中定义一个子类需要重写的方法,用@abstractmethod去装饰, 然后子类再去重写该方法,这就是工厂方法.

04 工厂方法模式的优点

通过上面的代码我们知道工厂方法模式有几个优点:

1、更大的灵活性, 代码更加通用, 不是单纯的实例化某个类. 实现哪些功能取决于客户端, 而非服务端.

2、松耦合性, 因为创建对象的代码与使用它的代码是分开的. 客户端不需要关心要传递的参数及实例化哪些类. 维护成本低.

05 抽象工厂模式

抽象工厂模式主要目的是提供一个接口来创建一系列相关对象, 而无需指定具体的类. 工厂方法将创建实例的任务委托给了子类, 抽象工厂方法的目标是创建一系列相关对象. 下面看代码:

# coding=utf-8


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__, " 在蔬菜上来点鸡肉 ", 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__, " 在蔬菜上来点火腿 ",type(VegPizza).__name__)


class PizzaStore:
    def makePizzas(self):
        factory = input("想吃Indian披萨还是US披萨? ").lower()
        if factory == "indian":
            self.factory = IndianPizzaFactory()
            self.NonVegPizza = self.factory.createNonVegPizza()
            self.VegPizza = self.factory.createVegPizza()
            self.VegPizza.prepare()
            self.NonVegPizza.serve(self.VegPizza)
        else:
            self.factory = USPizzaFactory()
            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()

咱们来讲解这段代码来理解抽象工厂.

1、首先创建PizzaFactory元类, 里面有两个工厂createVegPizza和createNonVegPizza.

2、定义PizzaFactory元类的子类IndianPizzaFactory和USPizzaFactory.

3、重写了createVegPizza和createNonVegPizza方法.

4、并分别返回了DeluxVeggiePizza和ChickenPizza, MexicanVegPizza和HamPizza

5、接着定义了VegPizza的元类, 里面有prepare工厂方法. 需要提供参数VegPizza.

6、定义了NonVegPizza元类, 里面有server工厂方法. 需要提供参数VegPizza.

7、定义了VegPizza的子类DeluxVeggiePizza, 重写了prepare方法.

8、定义了NonVegPizza子类ChickenPizza, 重写了serve方法.

9、定义了VegPizza的子类MexicanVegPizza, 重写了prepare方法.

10、定义了NonVegPizza子类HamPizza, 重写了serve方法.

11、最后定义PizzaStore类, 去调用实现过程.

代码中返回类, 让类去实现工厂中的方法实现即可. 上面的类翻译出来是: “意大利披萨”, “美国披萨”, “蔬菜披萨”, “非蔬菜披萨”, “墨西哥蔬菜披萨”, "火腿披萨"等,可以对照的中文在看上面的代码就好理解了.

06 工厂方法与抽象工厂对比

在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

算法小筑

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值