工厂模式简介
在面向对象编程中,术语“工厂”表示一个负责创建其他类型对象的类。通常情况下,作为一个工厂的类有一个对象以及与它关联的多个方法。客户端使用某些参数调用此方法,之后,工厂会根据此创建所需类型的对象,然后将它们返回给客户端。
工厂具有的优点:
1、松耦合,即对象的创建可以独立于类的实现
2、客户端无需了解创建对象的类,但是照样可以使用它来创建对象。它只需要知道需要传递的接口、方法和参数,就能够创建所需类型的对象。这简化了客户端的实现。
3、可以轻轻松松的在工厂中添加其他类来创建其他类型的对象,而无需更改客户端代码,最简单的情况下,客户端只需要传递另一个参数就可以了。
4、工厂还可以重用现有对象。但是,如果客户端直接创建对象的话,总是创建一个新对象。
工厂模式有三种变体:
1、简单工厂模式:允许接口创建对象,但是不会暴露对象的创建逻辑。
2、工厂方法模式:允许接口创建对象,但是用哪个类来创建对象,则是交由子类决定的。
3、抽象工厂模式:抽象工厂是一个能够创建一系列相关的对象而无需指定/公开其具体类的接口。该模式能够提供其他工厂的对象,在其内部创建其他对象
简单工厂模式
对于一些人来说,简单工厂本身不是一种模式。开发人员再进一步了解这个概念之前,首先需要详细了解工厂方法和抽象工厂方法。工厂可以帮助开发人员创建不同类型的对象,而不是直接将对象实例化。
from abc import ABCMeta, abstractmethod
class Animal(metaclass=ABCMeta):
@abstractmethod
def do_say(self):
pass
class Dog(Animal):
def do_say(self):
print("dog dog")
class Cat(Animal):
def do_say(self):
print("cat cat")
class ForestFactory(object):
def make_sound(self, object_type):
return eval(object_type)().do_say()
if __name__ == '__main__':
ff = ForestFactory()
animal = input("Dog or Cat?")
ff.make_sound(animal)
在上面的代码中,我们创建一个名为Animal的抽象产品。Animal是一个抽象的基类(ABCMeta是Python的特殊元类, 用来生成类Abstract),它带有方法do_say().我们利用Animal接口创建了两种产品(Dog和Cat),并且实现了do_say()方法来提供这些动物相应的叫声。ForestFactory是一个带有make_sound()方法的工厂。根据客户端传递的参数类型,他就可以在运行时创建适当的Animal实例,并正确输出
工厂方法模式
通过以下几点了解工厂方法模式:
1、我们定义一个接口来创建对象,但是工厂本身并不负责创建对象,而是将这一任务由子类完成,即子类决定了要实例化那些类。
2、Factory方法的创建是通过继承而不是通过实例化来完成的。
3、工厂方法使设计更加具有可定制性。它可以返回相同的实例或子类,而不是某种类型的对象
实现工厂方法
我们拿一个现实世界的场景来理解工厂方法夫人实现。假设我们先想在不同类型的社交网站(例如Linkedin、Facebook等)上为个人或者公司建立简介。那么,每个简介都有某些特定的组成章节。在Linkedin的简介中,有一个章节是关于个人申请的专利或出版作品。在Facebook上,你将在相册中看到最近度假地点的照片区。此外,在这两个简介中,都有一个个人信息区。因此,我们要通过将正确的区添加到相应的简介中来创建不同类型的简介。
下面用代码去具体的实现,首先定义接口Product。我们将创建一个Section抽象类来定义一个区使关于哪方面内容的,让它尽量保持简单,同时还提供一个抽象方法describe()。
然后,我们会创建多个ConcreteProduct、PersonalSection、AlbumSection、PatentSection和PublicationSection类。这些类用于实现describe()抽象方法并打印它们各自的区名称:
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")
我们创建了一个名为Profile的抽象类Creator。Profile[Creator]抽象类提供一个工厂方法,createProfile()方法应该由ConcreteClass实现,来实际创建带有适当区的简介。Profile抽象类不知道每个简介应具有那些区。例如,Facebook的简介应该提供个人信息区和相册区。所以我们将让子类来决定这些事情。
我们创建两个ConcreteCreator类,即LinkedIn和Facebook。每个类都实现createProfile()抽象方法,由该方法在运行时实际创建多个区(ConcreteProducts):
class Profile(metaclass=ABCMeta):
def __init__(self):
self.sections = []
self.create_profile()
@abstractmethod
def create_profile(self):
pass
def get_sections(self):
return self.sections
def add_sections(self, section):
self.sections.append(section)
class LinkedIn(Profile):
def create_profile(self):
self.add_sections(PatentSection())
self.add_sections(PatentSection())
self.add_sections(PublicationSection())
class FaceBook(Profile):
def create_profile(self):
self.add_sections(PersonalSection())
self.add_sections(AlbumSection())
最后开始写决定实例化那个Creator类的客户端代码,以便让它根据指定的选项创建所需的简介:
if __name__ == "__main__":
profile_type = input("LinkedIn or FaceBook")
profile = eval(profile_type)()
print("Creating Profile.. ", type(profile).__name__)
print("Profile has sections --", profile.get_sections())
工厂方法模式的优点:
1、它具有更大的灵活性,使得代码更加通用,因为它不是单纯地实例化某个类,这样实现那些类取决于接口。
2、它是松耦合的,因为创建对象的代码与使用它的代码是分开的。客户端完全不需要关心要传递那些参数以及需要实例化那些类。由于添加新类更加容易,所以降低了维护成本