设计模式系列之一:简单工厂模式
1.1 定义
简单工厂模式属于创建型模式,又称为静态工厂方法模式,在简单工厂模式中,可以根据参数的不同,来返回不同类的实例,简单工厂模式专门定义一个类来负责创建子类的实例,被创建的类通常有一个共同的父类
1.2 简单工厂模式结构图(简版)
Factory:工厂类,简单工厂模式的核心,它负责实现创建所有实例的内部逻辑。工厂类的创建产品类的方法可以被外界直接调用,创建所需的产品对象
IProduct:抽象产品类,简单工厂模式所创建的所有对象的父类,它负责描述所有实例所共有的公共接口
Product:具体产品类,是简单工厂模式的目标类
1.3 简单工厂的实现一
假设有一个电脑的代工生产商,它目前已经可以代工生产联想电脑了,随着业务的拓展,这个代工生产商还要生产惠普和mac电脑;
这样我们就需要用一个单独的类来专门生产电脑,这就用到了简单工厂模式,同时用到了继承、封装、多态等面向对象编程的思想,下面我们来实现简单工厂模式
1.3.1 产品抽象类
public abstract class Computer { /** * 产品的抽象方法,由具体的产品类去实现 */ public abstract void start(); }
1.3.2 具体实现类
public class LenovoComputer extends Computer { @Override public void start() { System.out.println("lenovo computer run"); } }
public class MacComputer extends Computer { @Override public void start() { System.out.println("Mac computer run"); } }
public class HpComputer extends Computer { @Override public void start() { System.out.println("hp computer run"); } }
1.3.3 工厂类
public class ComputerFactory { public static Computer createComputer(String type) { Computer computer = null; switch (type) { case "lenovo": computer = new LenovoComputer(); break; case "hp": computer = new HpComputer(); break; case "Mac": computer = new MacComputer(); break; default: break; } return computer; } }
1.3.4 UML类图
1.4 优缺点
优点:
1. 工厂类含有必要的判断逻辑,可以决定在什么时候创建哪一个产品类的实例,客户端可以免除直接创建产品对象的责任,而仅仅“消费”产品;实现了对责任的分割,它提供了专门的工厂类用于创建对象。
2. 客户端无须知道所创建的具体产品类的类名,只需要知道具体产品类所对应的参数即可,对于一些复杂的类名,通过简单工厂模式可以减少使用者的记忆量。
3. 通过引入配置文件,可以在不修改任何客户端代码的情况下更换和增加新的具体产品类,在一定程度上提高了系统的灵活性。
缺点:
1. 由于工厂类集中了所有产品创建逻辑,一旦不能正常工作,整个系统都要受到影响。
2. 使用简单工厂模式将会增加系统中类的个数,在一定程序上增加了系统的复杂度和理解难度。
3. 系统扩展困难,一旦添加新产品就不得不修改工厂逻辑,同样破坏了“开闭原则”;在产品类型较多时,有可能造成工厂逻辑过于复杂,不利于系统的扩展和维护。
4. 简单工厂模式由于使用了静态工厂方法,造成工厂角色无法形成基于继承的等级结构
1.5 适用场景
1. 工厂类负责创建的对象比较少:由于创建的对象较少,不会造成工厂方法中的业务逻辑太过复杂。
2. 客户端只知道传入工厂类的参数,对于如何创建对象不关心:客户端既不需要关心创建细节,甚至连类名都不需要记住,只需要知道类型所对应的参数。
1.6 模式应用
1. JDK类库中广泛使用了简单工厂模式,如工具类java.text.DateFormat,它用于格式化一个本地日期或者时间
public final static DateFormat getDateInstance(); public final static DateFormat getDateInstance(int style); public final static DateFormat getDateInstance(int style,Locale locale);2. 获取不同加密算法的密钥生成器
KeyGenerator keyGen=KeyGenerator.getInstance("DESede");
1.7 开闭原则
对于上面两种简单工厂模式的实现方法,如果我们要添加新的 parser,那势必要改动到 RuleConfigParserFactory 的代码,那这是不是违反开闭原则呢?
实际上,如果不是需要频繁地添加新的 parser,只是偶尔修改一下 RuleConfigParserFactory 代码,稍微不符合开闭原则,也是完全可以接受的。
尽管简单工厂模式的代码实现中,有多处 if 分支判断逻辑,违背开闭原则,但权衡扩展性和可读性,这样的代码实现在大多数情况下(比如,不需要频繁地添加 parser,也没有太多的 parser)是没有问题的