问题
考虑一个常见的场景,我们需要设计一个订单Order类和客户Consumer类,开始时,由于需求比较简单,为了加快速度,我们在需要订单的地方都通过‘new Order()’ 进行订单的创建,一切都很正常,程序运行良好。
对于开发而言,唯一不变的便时“变化”,因此,过来一段时间之后,新的需求来了,在创建订单对象的时候,必须要关联一个客户,如果没有客户,则新创建的订单是没有意义的,非常合理。那现在就要修改之前的程序了,在修改之前,我们做如下考虑:
1. 你创建一个新的构造函数,其中需要一个客户Customer的参数,而这个构造函数仅仅针对后续订单对象的创建使用。(这明显不可接受,之前的咋办?)
2. 针对每个使用new 创建的地方进行逐次修改(最简单也是最痛苦的修改~~~~大部分程序员应该都经历过的~)
3. 假设我们按照2修改过了,运行一段时间之后,又出现了新的需求,一个订单不仅需要一个客户对象,而且还需要一个商家的对象,那我们又该如何应对?再追个修改一遍?
针对上述的解决方案,如果第一次我们做了一次修改,第二次还要重复前一次的步骤,是一个不合格的程序员,也就只能做点简单复制、粘贴的工作了,相信看这篇文章的你,肯定不是这样的,那我们该如何解决这个问题呢?那便是工厂模式
什么是工厂模式
工厂模式定义了一个创建对象的接口,但由于子类决定要实例化的类是哪一个,工厂方法让类把实例化推迟到子类,此外通过该模式,不需要暴露对象创建的过程,只需要进行一次简单的调用便可拿到我们需要的对象,非常方便使用。
解决方案
我们介绍了什么是工厂模式,也提出了我们的问题,那工厂模式是怎样解决我们前面遇到的问题的呢?我们可以创建一个订单的工厂类,提供一个静态的工厂方法,如createOrder(),在该方法中创建一个Order对象,并将该对象的引用返回给调用者;现在,我们可以发现,所有订单对象的创建都在一个地方了,我们可以肆无忌惮的调用了,如果需求变了,咋办?仅仅修改工厂方法就可以了,所有调用端都是无感的,非常好的应对了需求的变更。
如下所示:
public class OrderFactory {
public static Order getOrder(){
Order order = new Order();
// 对order对象继续进行后续的逻辑填充,全部在一个地方
return order;
}
}
而这只是工厂模式解决的众多问题中的一个,工厂模式可以解决更多的问题,详情请看下面的“应用场景”部分。
所带来的好处
-
对象的创建统一在一个地方,方便后续的变更和维护,增加了扩展性
-
可以隐藏对象的创建细节
-
可以延迟类的实例化,在运行时根据条件进行子类的实例化
-
解耦了调用者与类之间的关系
-
相较于构造方法,我们可以起一个更具有表达性的名称
所带来的弊端
-
增加了代码的复杂度,如果每个类都创建一个工厂类,则会使类的数量翻倍
-
增加了系统具体类的依赖
应用场景
-
问题所反映的,由于需求的变更,导致多处进行修改
-
类的实例化是在运行时根据条件,实例化子类时
public class CarFactory { public static Car getCar(String type) { Car car = null; if ("small".equals(type)) { car = new SmallCar(); } else if ("suv".equals(type)) { car = new SUVCar(); } return car; } }
如上,可以根据传入的参数type进行子类的创建。
-
如果创建对象的过程特别复杂,如需要进行各种参数的验证、条件的判定和依赖需要其他对象等
注意点
作为一种创建类模式,在任何需要生成复杂对象的地方,都可以使用工厂方法模式。有一点需要注意的地方就是复杂对象适合使用工厂模式,而简单对象,特别是只需要通过 new 就可以完成创建的对象,无需使用工厂模式。如果使用工厂模式,就需要引入一个工厂类,会增加系统的复杂度。
引用
Factory Pattern. When to use factory methods? - Stack Overflow