#工厂模式:建立创建对象的工厂
在面向对象编程中,术语“工厂”表示一个负责创建其他类型对象的类。通常情况下,作为一个工厂的类有一个对象以及与它关联的多个方法。客户端使用某些参数调用此方法之后,工厂会据此创建所需类型的对象,然后将它们返回给客户端。 工厂具有下列优点:松耦合,即对象的创建可以独立于类的实现;客户端无需了解创建对象的类,但是照样可以使用它来创建对象。它只需要知道需要传递的接口、方法和参数,就能够创建 所需类型的对象了。这简化了客户端的实现;可以轻松地在工厂中添加其他类来创建其他类型的对象,而这无需更改客户端代码。最简单的情况下,客户端只需要传递一个参数就可以了;工厂还可以重用现有对象。但是,如果客户端直接创建对象的化,总是创建一个新对象。
Factory模式有3种变体: (1)简单工厂模式: 允许接口创建对象,但不会暴露对象的创建逻辑。 (2)工厂方法模式:允许接口创建对象,但使用哪个类来创建对象,则是交由子类决定的。 (3)抽象工厂模式:抽象工厂是一个能够创建一系列相关的对象而无需指定/公开其具体类的接口。该模式能够提供其他工厂的对象,在其内部创建其他对象。##一、简单工厂模式
工厂可以帮助开发人员创建不同类型的对象,而不是直接将对象实例化。
下图是简单工厂的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('喵喵。。。') #工厂类: class ForestFactory: def make_sound(self, object_type): return eval(object_type)().do_say() #client code if __name__ == '__main__': ff = ForestFactory() animal = input('Which animal should make sound(Dog or Cat)?') ff.make_sound(animal)##二、工厂方法模式
以下几点可以帮助我们了解工厂方法模式: (1)我们定义了一个接口来创建对象,但是工厂本身并不负责创建对象,而是将这以任务交由子类来完成,即子类决定了要实例化哪些类; (2)Factory方法的创建是通过继承而不是通过实例化来完成的; (3)工厂方法使设计更加具有可定制性。它可以返回相同的实例或子类,而不是某种类型的对象。
在UML图中,有一个包含factoryMethod()方法的抽象类Creator。factoryMethod()方法负责创建指定类型的对象。ConcreteCreator类提供了一个实现Creator抽象类的factoryMethod()方法,这种方法可以在运行是时修改已创建的对象。ConcreteCreator创建ConcreteProduct,并确保其创建的对象实现了Product类,同时为Product接口中的所有方法提供相应的实现。 简而言之,Creator接口的factoryMethod()方法和ConcreteCreator类共同决定了要创建Product的哪个子类。因此,工厂方法模式定义了一个接口来创建对象,但具体实例化哪个类则是由它的子类决定的。
from abc import ABCMeta, abstractmethod #抽象Product class Section(metaclass = ABCMeta): @abstractmethod def describe(self): #抽象方法 pass #ConcreteProduct1 class PersonalSection(Section): def describe(self): print('Personal Section!') #ConcreteProduct2 class AlbumSection(Section): def describe(self): print('Album Section!') #ConcreteProduct3 class PatentSection(Section): def describe(self): print('Patent Section!') #ConcreteProduct4 class PublicationSection(Section): def describe(self): print('Publication Section!') #抽象类Creator class Profile(metaclass = ABCMeta): def __init__(self): self.sections = [] self.createProfile() @abstractmethod def createProfile(self): pass def getSections(self): return self.sections def addSectons(self, section): self.sections.append(section) #ConcreteCreator类 class linkedin(Profile): def createProfile(self): self.addSectons(PersonalSection()) self.addSectons(PatentSection()) self.addSectons(PublicationSection()) #ConcreteCreator类 class facebook(Profile): def createProfile(self): self.addSectons(PersonalSection()) self.addSectons(AlbumSection()) if __name__ == '__main__': profile_type = input('Which Profile you\'d like to create?(LinkedIn or FaceBook)') profile = eval(profile_type.lower())() #实例化类 print('Creating Profile...:', type(profile).__name__) print('Profile has sections...:', profile.getSections())工厂方法模式的优点: (1)它具有更大的灵活性,使得代码更加通用,因为它不是单纯地实例化某个类。这样,实现哪些类取决于接口(Product),而不是ConcreteCreator。 (2)它们是松耦合的,因为创建对象的代码与使用它的代码是分开的。客户端完全不需要关心要传递哪些参数以及需要实例化哪些类。由于添加新类更加容易,所以降低了维护成本。
##三、抽象工厂模式 抽象工厂模式的主要目的是提供一个接口来创建一系列相关对象,而无需指定具体的类。工厂方法将创建实例的任务委托给了子类,而抽象工厂方法的目标是创建一系列相关对象。如图3所示,ConcreteFactory1 和 ConcreteFactory2 是通过AbstractFactory接口创建的。此接口具有创建多种产品的相应方法。 ConcreteFactory1 和 ConcreteFactory2实现了AbstractFactory,并创建实例ConcreteProduct1、ConcreteProduct2、AnotherConcreteProduct1和AnotherConcreteProduct2。 在这里,ConcreteProduct1和ConcreteProduct2是通过AbstractProduct接口创建的,而AnotherConcreteProduct1和AnotherConcreteProduct2则是通过AnotherAbstractProduct接口创建的。 实际上,抽象工厂模式不仅确保客户端与对象的创建相互隔离,同时还确保客户端能够使用创建的对象。但是,客户端只能通过接口访问对象。如果要使用一个系列中的多个产品,那么抽象工厂模式能够帮助客户端一次使用来自一个产品/系列的多个对象。 ###实现抽象工厂模式 例子:一家披萨店,供应印式和美式披萨饼。为此,我们首先创建一个抽象基类—PizzaFactory(AbstractFactory)。PizzaFactory类有两个抽象方法即createVegPizza()和createNonVegPizza(),它们需要通过ConcreteFactory实现。在这个例子中,我们创建了两个具体的工厂,分别名为IndianPizzaFactory和USPizzaFactory。
from abc import ABCMeta, abstractmethod #AbstractFactory class PizzaFactory(metaclass = ABCMeta): @abstractmethod def createVegPizza(self): pass @abstractmethod def createNonVegPizza(self): pass #ConcreteFactory class IndianPizzaFactory(PizzaFactory): def createVegPizza(self): return DeluxVeggiePizza() def createNonVegPizza(self): return ChickenPizza() #ConcreteFactory class USPizzaFactory(PizzaFactory): def createVegPizza(self): return MexicanVegPizza() def createNonVegPizza(self): return HamPizza() #进一步定义 AbstractProducts: #AbstractProduct class VegPizza(metaclass = ABCMeta): @abstractmethod def prepare(self, VegPizza): #定义自己的方法 pass #AnotherAbstractProduct class NonVegPizza(metaclass = ABCMeta): @abstractmethod def serve(self, VegPizza): #定义自己的方法 pass #为每个AbstractProducts定义ConcreteProducts,创建DeluxVeggiePizza和MexicanVegPizza: class DeluxVeggiePizza(VegPizza): #ConcreteProducts1 def prepare(self): print('Prepare:', type(self).__name__) #定义AnotherConcreteProduct: class MexicanVegPizza(VegPizza): #ConcreteProducts2 def prepare(self): print('Prepare:', type(self).__name__) #定义ChickenPizza和HamPizza,分别代表AnotherConcreteProducts1和AnotherConcreteProducts2: class ChickenPizza(NonVegPizza): #AnotherConcreteProducts1 def serve(self, VegPizza): print(type(self).__name__, ' is served with Chicken on ', type(VegPizza).__name__) class HamPizza(NonVegPizza): def serve(self, VegPizza): print(type(self).__name__, ' is served with Ham on ', type(VegPizza).__name__) #当最终用户来到PizzaStore并要一份美式非素食披萨的时候,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) if __name__ == '__main__': pizza = PizzaStore() pizza.makePizzas()###工厂方法与抽象工厂方法
工厂方法抽象工厂方法它向客户端开发了一个创建对象的方法抽象工厂方法包含一个或多个工厂方法来创建一个系列的相关对象它使用继承和子类来决定要创建哪个对象它使用组合将创建对象的任务委托给其他类工厂方法用于创建一个产品抽象工厂方法用于创建相关产品的系列