1.了解工厂模式
“工厂”表示一个负责创建其他类型对象的类。通常情况下,作为一个工厂的类有一个对象以及与它关联的多个方法。客户端使用某些参数调用此方法,之后,工厂会据此创建所需类型的对象,然后将它们返回给客户端。
优点:
- 松耦合:对象的创建可独立于类的实现
- 客户端无需了解创建对象的类,只需知道需要传递的接口、方法和参数。简化了客户端的实现
- 可以轻松地在工厂中添加其他类来创建其他类型对象,无需更改客户端代码。
- 可重用现有对象
2.简单工厂模式
允许接口创建对象,但不会暴露对象的创建逻辑。
参看如下示例:
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('Which animal should make_sound,Dog or Cat?')
ff.make_sound(animal)
输出如下:
Which animal should make_sound,Dog or Cat?>? Dog
汪汪
元类是类的类,其实例就是一个类。Python中一切皆对象,默认的元类是type,其他都是type的实例。
其中,ABCMeta是Python的特殊元类,用于生成抽象基类(Abstract)。Animal是一个抽象基类,带有方法do_say()。利用Animal接口创建了两种产品,并实现了do_say()方法提供这些动物的叫声。ForestFactory是一个带有make_sound()方法的工厂。根据客户端传递的参数类型,它就可以在运行时创建适当的Animal实例,并输出正确的声音。
3 工厂方法模式
以下几点可以帮助我们了解工厂方法模式:
- 定义一个接口创建对象,但工厂本身并不负责创建对象,而是将这一任务交由子类完成,即子类决定要实例化哪些内容
- Factory方法的创建时通过继承而不是通过实例化完成的
- 工厂方法使设计更加具有可定制性。它可以返回相同的实例或子类,而不是某种类型的对象。
参看如下例子:
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("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())
解析:
假设想在不同类型的社交网络上为个人或公司建立简介。那么,每个简介都有某些特定的组成章节,同时也有公共的章节。简而言之,我们要通过将正确的区添加到相应的简介中来创建不同类型的简介。
创建一个Section抽象类来定义一个区是关于哪方面内容的。这个Section抽象类被称为接口Product。
随后建立PersonalSection、AlbumSection、PatentSection和PublicationSection类。这些类被称为ConcreteProduct。都是Section的子类。
创建一个名为Profile的抽象类Creator。Profile抽象类提供一个工厂方法,即createProfile()。createProfile()方法应该由ConcreteClass实现,来实际创建带有适当区的简介。Profile抽象类不知道每个简介应具有哪些区,所以让子类来决定这些事情。
创建两个ConcreteCreator类,linkedin和facebook。每个类实现createProfile()抽象方法,由该方法在运行时实际创建多个区。
Creator接口的factoryMethod()方法和ConcreteCreator类工图决定了要创建Product的哪些子类。因此,工厂方法模式定义了一个接口来创建对象,但具体实例化哪个类则是由它的子类决定。
工厂方法使一个类的实例化延迟到其子类,可以不修改原有的工厂类。工厂方法模式实现时,客户端需要决定实例化哪一个工厂来实现具体类。工厂方法将简单工厂的内部逻辑判断移到了客户端代码来进行。
工厂方法模式的优点:
- 具有更大的灵活性,使得代码更加通用,因为它不是单纯地实例化某个类。这样,实现哪些类取决于接口(Product)。而不是ConcreteProduct类。
- 它们是松耦合的,因为创建对象的代码与使用它的代码是分开的。客户端完全不需要关心要传递哪些参数以及需要实例化哪些类。由于添加新类更加容易,所以降低了维护成本。
4 抽象工厂模式
主要目的:提供一个接口创建一系列相关对象,而无需指定具体的类。工厂方法将创建实例的任务委托给了子类,而抽象工厂方法的目标是创建一系列相关对象。
实际上,抽象工厂模式不仅确保客户端与对象的创建相互隔离,同时还确保客户端能够使用创建的对象。但是,客户端只能通过接口访问对象。
如果要使用一个系列中的多个产品,那么抽象工厂模式能够帮助客户端一次使用来自一个产品/系列的多个对象。
例如:正在开发的应用应该是平台无关的,则它需要对各种依赖项进行抽象处理,包括操作系统、文件系统调用,等等。抽象工厂模式负责为整个平台创建所需的服务,如此,客户端就不必直接创建平台对象。
参看如下实例:
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):
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)
pizza=PizzaStore()
pizza.makePizzas()
输出如下:
Prepare DeluxVeggiePizza
ChickenPizza is served with Chicken on DeluxVeggiePizza
Prepare MexicanVegPizza
HamPizza is served with Ham on MexicanVegPizza
上例中:
- 抽象工厂:PizzaFactory
- 具体工厂:IndianPizzaFactory和USPizzaFactory
- 抽象产品:VegPizza和NonVegPizza
- 具体产品:DeluxVeggiePizza和MexicanVegPizza、ChickenPizza和HamPizza
5 工厂方法与抽象工厂方法
工厂方法 | 抽象工厂方法 |
---|---|
向客户端开放了一个创建对象的方法 | 包含一个或多个工厂方法来创建一个系列的相关对象 |
使用继承和子类来决定要创建哪个产品 | 使用组合将创建对象的任务委托给其他类 |
工厂方法用于创建一个产品 | 抽象工厂方法用于创建相关产品的系列 |
抽象工厂方法的优点与缺点
优点
- 便于交换产品系列,由于具体工厂类在一个应用中只需要在初始化时出现一次,这就使得改变一个应用的具体工厂变得非常容易,它只需要改变具体工厂即可使用不同的产品配置
- 让具体的创建实例过程与客户端分离,客户端通过它们的抽象接口操纵实例,产品的具体类名也被具体工厂的实现分离,不会出现在客户代码中