引入-简单工厂模式的不足
- 简单工厂模式最大的缺点是当有新产品要加入到系统中时,必须修改工厂类,加入必要的处理逻辑,违背了开闭原则。
- 在简单工厂模式中,所有的产品都是由同一个工厂创建,工厂类职责较重,业务逻辑复杂,具体类与工厂类之间的耦合度较高,严重影响了系统的扩展性和灵活性
模式定义
- 工厂方法模式又称为工厂模式、虚拟构造器模式、多态工厂模式,它属于创建型模式
- 在工厂模式中,工厂父类负责定义创建产品对象的公共接口,而工厂子类负责创建具体的产品对象,这样做可以将产品类的实例化操作延迟到工厂子类中完成
模式结构与分析
模式结构图
模式角色如下
- 抽象产品Product
抽象产品是定义产品的接口,是产品对象的共同父类或接口 - 具体产品ConcreteProduct
具体产品实现了抽象产品接口,某种具体类型的产品由专门的具体工厂创建,它们之间是一一对应的关系 - 抽象工厂Factory
在抽象工厂类中声明了工厂方法,用语返回一个产品。所有创建产品对象的具体工厂都必须实现这一接口 - 具体工厂ConcreteFactory
具体工厂是抽象工厂的子类,它实现了抽象工厂中定义的工厂方法,由应用程序调用,返回一个具体的产品对象的实例
模式实例与解析
- 实例说明
某系统日志记录器要求支持多种日志记录方式,如文件记录、数据库记录等,且用户可以根据要求动态选择日志记录方式,现使用工厂方法模式设计该系统 - 实例类图
- 代码实现
抽象产品类Log
class Log(ABC):
'''抽象产品类'''
@abstractclassmethod
def writeLog(self):
pass
class FileLog(Log)
具体产品类FileLog
class FileLog(Log):
'''具体产品类'''
def writeLog(self):
print('从文件写入日志记录')
具体产品类DataBaseLog
class DataBaseLog(Log):
'''具体产品类'''
def writeLog(self):
print('从数据库中写入日志记录')
抽象工厂类LogFactory
class LogFactory(ABC):
'''抽象工厂类'''
@abstractclassmethod
def createLog(self):
pass
具体工厂类FileLogFactory
class FileLogFactory(LogFactory):
'''具体工厂类'''
def createLog(self):
print('创建文件日志')
具体工厂类DataBaseLogFactory
class DataBaseLogFactory(LogFactory):
'''具体工厂类'''
def createLog(self):
print('创建数据库日志')
return DataBaseLog()
测试代码
factory = DataBaseLogFactory()
log = factory.createLog()
log.writeLog()
结果
模式优缺点
优点
- 在工厂方法模式中,用户只需要关心所需产品对应的工厂,而不需要关心产品创建的细节,甚至不需要知道具体产品类的类名
- 基于工厂角色和产品角色的多态性设计使得工厂方法模式可以自主确定创建何种产品对象
- 在系统中加入一个新产品时,只要加入具体的产品类和具体的工厂即可,系统扩展性好,符合开闭原则
缺点
- 添加新产品时,系统中类的个数成对增加(具体产品和具体工厂),一定程度上增加了系统的复杂度,给系统带来了一些额外的开销
- 抽象层使得系统的理解难度增加
模式适用环境
- 一个类不知道它所需要的对象的类
由于在工厂方法模式中客户端只需知道创建产品对象的工厂类名,而不知道具体产品对象的类名 - 一个类通过其子类来指定创建哪个对象
- 将创建对象的任务交给多个工厂子类中的某一个
模式应用
1.Java集合框架中的java.util.Collection接口的**iterator()**工厂方法使得具体的java集合类可以通过实现该方法返回一个Iterator迭代器对象
2.Java消息服务JMS的实现广泛使用工厂方法模式
3.JDBC中也大量使用工厂方法模式,例如在创建连接对象Connection、语句对象Statement和结果集对象ResultSet时都使用工厂方法
模式扩展
1.使用多个工厂方法
在抽象工厂类中定义多个多个工厂方法,让具体工厂角色实现这些不同的工厂方法,完成不同的业务功能,满足不同的产品对象的功能
2.产品对象的重复使用
- 在实际情况中工厂方法所做的事可以非常复杂,一个常用的复杂逻辑就是重复使用产品对象
- 工厂对象将已经创建过的产品保存到一个集合(数组,List)中,然后根据客户对产品的要求,从集合中查询。如果集合中没有满足需求的产品对象,则创建一个新的满足要求的产品对象并加入到集合中,返回给客户端,这是享元模式的设计思想
3.多态性的丧失和模式的退化
当只有一个具体工厂,具体工厂中创建所有的产品对象,并且将工厂方法设计为静态方法时,工厂方法模式就退化为简单工厂模式
实验
问题描述
现需要设计一个程序来读取多种不同类型的图片格式,针对每一种图片格式设计一个图片读取器(ImageReader),如GIF图片读取器(GifReader)用于读取GIF格式的图片,JPEG图片读取器(JpgReader)用于读取JPEG格式的图片。
UML图
设计代码
- 抽象产品类ImgReader
class ImgReader(metaclass=ABCMeta):
'''抽象图片读取类'''
@abstractclassmethod
def read(self):
'''抽象读取方法'''
pass
- 具体产品类JpgReader和GifReader
class JpgReader(ImgReader):
'''jpg格式照片'''
def read(self):
print('读取jpg格式的照片')
class GifReader(ImgReader):
'''gif格式的照片'''
def read(self):
print('读取gif格式的照片')
- 抽象工厂类ReaderFactory
class ReaderFactory(metaclass=ABCMeta):
'''抽象工厂'''
@abstractclassmethod
def create_reader(self):
'''抽象制造读取器'''
pass
- 具体工厂类JpgReaderFactory和GifReaderFactory
class JpgReaderFactory(ReaderFactory):
'''jpg格式图片读取器工厂'''
def create_reader(self):
return JpgReader()
class GifReaderFactory(ReaderFactory):
'''gif格式图片读取器工厂'''
def create_reader(self):
return GifReader()
小结
- 工厂方法模式又称工厂模式,属于类创建型模式
- 工厂方法包含4个角色:抽象产品、具体产品、抽象工厂、具体工厂
- 工厂方法是简单工厂模式的进一步抽象和推广
- 工厂方法的优点
- 工厂方法的适用情况