工厂模式可以说是最常用的设计模式. 我们分几个主题介绍:
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类, 去调用实现过程.
代码中返回类, 让类去实现工厂中的方法实现即可. 上面的类翻译出来是: “意大利披萨”, “美国披萨”, “蔬菜披萨”, “非蔬菜披萨”, “墨西哥蔬菜披萨”, "火腿披萨"等,可以对照的中文在看上面的代码就好理解了.