意图:定义一个用于创建对象的接口,让子类决定实例化哪一个类。Factory Method使一个类的实例化延迟到其子类。
结构:
示例:
Product(Document):被工厂方法生产的产品的抽象。
class Document(ABC):
def __init__(self, name):
self.name = name
@abstractmethod
def open(self):
"""打开文档"""
def save(self):
print('save %s.' % self.name)
def revert(self):
print('revert %s.' % self.name)
ConcreteProduct(DrawingDocument、TextDocument):具体的产品类。
class DrawingDocument(Document):
def open(self):
print('open %s with 画图.' % self.name)
class TextDocument(Document):
def open(self):
print('open %s with 写字板.' % self.name)
Creator(Application):声明了工厂方法(create_document())的工厂类,可以调用工厂方法生产一个产品类。
class Application(ABC):
def __init__(self):
self.docs = []
@abstractmethod
def create_document(self, name):
"""创建文档"""
def new_document(self, name):
"""新建并打开文档"""
doc = self.create_document(name)
self.docs.append(doc)
doc.open()
ConcreteCreator(DrawingApplication、TextApplication):具体的工厂类,实现工厂方法并返回具体的ConcreteProduct对象。
class DrawingApplication(Application):
def create_document(self, name):
return DrawingDocument(name)
class TextApplication(Application):
def create_document(self, name):
return TextDocument(name)
Client:
drawing_app = DrawingApplication()
drawing_app.new_document('kobe.jpg')
drawing_app.new_document('jordan.png')
print(list(map(lambda d: d.name, drawing_app.docs))) # ['kobe.jpg', 'jordan.png']
text_app = TextApplication()
text_app.new_document('冰与火之歌.txt')
text_app.new_document('三国演义.txt')
print(list(map(lambda d: d.name, text_app.docs))) # ['冰与火之歌.txt', '三国演义.txt']
简单工厂:利用传入参数的不同生产所需的产品对象。
def create_document(document_type, document_name):
"""
根据传入文档类型的不同,生产不同的文档对象
:param document_type:
:param document_name:
:return:
"""
if document_type == 'DRAWING':
return DrawingDocument(document_name)
elif document_type == 'TEXT':
return TextDocument(document_name)
分析:
利用简单工厂生产产品时,每当新增一个产品,就需要修改一次代码,利用工厂模式时,每新增一个产品则只需新增一个具体工厂。除此之外将工厂方法作为工厂类的静态方法,使要增加产品是则继承该工厂类。
class Creator: @staticmethod def create_document(document_type, document_name): """ 根据传入文档类型的不同,生产不同的文档对象 :param document_type: :param document_name: :return: """ if document_type == 'DRAWING': return DrawingDocument(document_name) elif document_type == 'TEXT': return TextDocument(document_name) else: raise TypeError('no document') class SubCreator(Creator): @staticmethod def create_document(document_type, document_name): """ 根据传入文档类型的不同,生产不同的文档对象 :param document_type: :param document_name: :return: """ if document_type == 'NEW': return NewDocument(document_name) else: super().create_document(document_type, document_name)
工厂方法通常在Template Methods中被调用。在上面的文档例子中,NewDocument就是一个模板方法。
- 简单工厂:我只有一个工厂,可以造汽车,飞机。某天需要造轮船,则需要改工厂内部结构。
- 工厂模式:我有汽车工厂,飞机工厂,某天我要造轮船,则重新新建一个轮船工厂,而不用改之前的其他工厂。