设计模式-工厂模式
工厂顾名思义就是创建产品,本质就是用工厂方法代替new
操作创建一种实例化对象的方式。根据不同的实现方式和抽象级别又可分为简单工厂,工厂方法和抽象工厂三种模式。
案例
需求
封装一个SqlHelper类,实现对SqlServer的操作,且后续可能需要同时支持SqlServer,MySql,Oracle等主流数据库。
这是我们平常非常熟悉的需求了,根据需求我们可以得到如下类图:
简单工厂
UML类图
我们将前面SqlHelper例子中的类图进行一次抽象,就得到更通用的简单工厂模式类图了。其中对应关系如下:
Client:SqlHelper
SimpleFactory:DbConnectionFactory
AbstractProduct:DbConnection
Product1、Product2:SqlConnection、MySqlConnection
定义
简单工厂模式是由一个工厂对象决定创建出哪一种产品类的实例。由于简单工厂通常会使用静态方法实现,因此也叫做静态工厂模式,它不属于23种GOF设计模式之一。
优缺点
优点
实现了对责任的分割,隔离了变化,因为它提供了专门的工厂类用于创建对象。
通过配置文件,可以在不修改任何客户端代码的情况下更换和增加新的具体产品类,在一定程度上提高了系统的灵活性。
缺点
集中了所有实例的创建逻辑,违反了单一职责原则
扩展困难,一旦添加新产品就不得不修改工厂逻辑,违反了开闭原则
工厂方法
案例改进
由于简单工厂模式不满足开闭原则,因此,我们需要对其进行改进,将简单工厂进行一次抽象,然后让每个具体的工厂子类负责生产对应的产品,具体改进如下:
UML类图
同样的,我们进行一次抽象,就得到工厂方法模式的类图了。
定义
定义一个工厂父类,工厂父类负责定义创建对象的公共接口,而子类则负责生成具体的对象。即将类的实例化延迟到工厂类的子类中完成,即由子类来决定应该实例化哪一个类。
优缺点
优点: 满足各种设计原则
缺点:类的个数成倍增加,增加了系统的复杂度
抽象工厂
需求扩展(参数化查询)
当然,我们知道,工作中,更通用SqlHelper没有这么简单,比如,我们至少需要参数化查询,防止用户的SQL脚本注入攻击。根据工厂方法模式的思路进一步改进,如下图所示:
不难发现,随着需求的增加,会出现如下问题:
类的数量成倍增长
无法保证类之间的依赖关系
改进
基于这些问题,我们继续改进,将多个相互关联的工厂(DbConnect和DbParameter使用时通常有密切联系)合并,得到如下类图:
UML类图
总结出更抽象的类图如下:
定义
抽象工厂是工厂方法的升级版,为相关或者相互依赖的对象提供一个统一的接口,而且无需指定他们的具体实现类。
优缺点
优点
对产品族进行约束,封装性好
缺点
产品族扩展困难,添加一个产品需要修改抽象和具体工厂类,违背开闭原则。
总结
简单工厂模式由于违背了众多设计原则,因此,很多时候会被视为是一种反模式而不是设计模式,但是由于面向对象设计语言中反射机制的存在,使得简单工厂模式使用的反而最为广泛;
工厂方法虽然时最满足设计原则的,但是由于它会使系统变得过于复杂,因此,反而用的最少;
抽象工厂模式更多体现的对产品族的约束,同时,相对于工厂方法模式,也降低了系统的复杂度,极端情况下,如果抽象工厂模式中的产品族只有一个产品,那么抽象工厂模式也就退化成了工厂方法模式。因此,很多人说抽象工厂模式是工厂的工厂,此观点是值得商榷的。