1. 什么是工厂模式
工厂模式是一种创建型模式,所以是被用来创建对象的,也是最常使用的一种设计模式。它为创建各种复杂的大对象提供了简便的方式。在工厂模式中,我们在创建对象时不会对客户端暴露创建逻辑,而是通过使用一个统一的出口来创建的对象。
联想:生活中的工厂,工厂里有很多流水线,可以生产不同的产品,而一个工厂和这些产品一定是属于同一个类型的。比如汽车工厂生产的是各种汽车,它肯定不会生产食品,甚至是汽车零件!汽车的零件是由零件加工工厂生产的,汽车工厂只负责装配。而对买方来说,买房只需要告诉工厂需要什么,工厂自会为其生产,而不需要知道生产的细节。
2. 使用的场景
开发过程中总是伴随着创建大量的对象,当有些对象比较复杂庞大并且高度相似(具有相同的功能)的时候,我们就可以采用工厂模式统一管理这些对象的创建。这对调用者来说更加的方便直观,而且也更加安全,因为工厂是预先设计好的,当满足工厂的生产条件后才会生产产品。相反,如果是比较简单的对象,那就完全没必要采取这种方式,直接new就行了。
工厂模式大多在框架中常见,因为它主要是为调用者(我们这些普通的开发人员)提供一个创建对象的出口,这些工厂类最大的特点就是它们的名字很明显—xxxFactory。例如连接各种数据库的ConnectionFactory,日志的LoggerFactory,Spring中核心的BeanFactory等等。当然,我们也可以自己设计出工厂类来管理自己的对象。
3. 怎么使用
理论和生活中的例子说完了,接下来步入正题,怎么在代码中去使用工厂模式。其实每种设计模式都能在生活中找到它们的例子,当然更可以说代码本身就是现实的一种抽象。上面说到,当一些对象高度相似即具有相同功能的时候,就可以使用工厂模式去创建。而具有某种功能在Java中就是实现某个接口,所以是通过一些类共同实现某个接口,再由一个工厂类根据不同的条件(参数)来创建相应的对象。而返回的是接口类型,也就是说还是一个抽象,这时调用接口里定义的方法,根据Java的多态机制,会准确找到实现类并执行方法。这样还有一个好处就是扩展性比较好,当有新的需求的时候就加一个实现类。
下面以一个手机工厂为例子,通过UML类图和示例代码介绍工厂模式是如何设计并工作的。
3.1. UML类图

3.2. 示例代码
1. 创建Mobile接口,并定义一个use的抽象方法
Mobile.java
public interface Mobile { void use(); }
2. 创建实现该接口的各个实现类
Iphone.java
public class IPhone implements Mobile { @Override public void use() { System.out.println("装逼"); } }
Nokia.java
public class Nokia implements Mobile{ @Override public void use() { System.out.println("挡子弹"); } }
Samsung.java
public class Samsung implements Mobile { @Override public void use() { System.out.println("爆炸"); } }
3. 创建一个手机工厂类MobileFactory,提供一个统一的出口getMobile方法来根据不同的条件创建相应的对象
MobileFactory.java
public class MobileFactory { public Mobile getMobile(String brand) { if (brand == null) { return null; } switch (brand) { case "iPhone" : return new IPhone(); case "Nokia" : return new Nokia(); case "Samsung" : return new Samsung(); default: throw new RuntimeException("本工厂暂不生产此品牌的手机!"); } } }
这里我们是根据不同的品牌来创建对应的手机对象,而实际中的条件要稍微复杂一些。可以把方法改为static,这样使用工厂类创建对象就不用先new工厂对象,比较简单就不贴代码了。
4. 使用该工厂类,通过传递不同的品牌参数来生成不同的对象
public class FactoryPatternDemo { public static void main(String[] args) { Mobile iPhone = MobileFactory.getMobile("iPhone"); iPhone.use(); Mobile nokia = MobileFactory.getMobile("Nokia"); nokia.use(); Mobile samsung = MobileFactory.getMobile("Samsung"); samsung.use(); } }
5. 输出:
装逼 挡子弹 爆炸
4. 总结
当我们需要实现某个明确的功能而这种功能通常具有普遍性时候,我们就可以使用工厂模式了。什么是普遍性呢,简单来说就是这个功能说起来比较宽泛,但是实际上会有不同的明确实现。还是举一些例子:
例如要开发一个计算器,计算机的核心功能是计算,而计算这个功能是比较宽泛的,实际上是有很多不同的明确实现,最常见的就是加减乘除。这时就可以创建一个计算接口,再分别创建加减乘除四个实现类,最后创建一个计算器的工厂类,通过用户传来的运算符号决定具体采用哪种运算。这样以后扩展计算器的功能,例如对数指数微积分等高级运算,就完全可以按照这种模式去横向扩展。
再比如我们的系统现在需要实现一个报警功能,当代码出现错误或系统崩溃时能够及时的通知相关人员。还是老样子,报警说起来是一回事,但具体实现上有不同的途径:邮件、短信、站内信等等。这时也可以采用工厂设计模式,根据不同的情况采用不同的报警。
4.1. 优点
解耦、方便调用者创建对象、扩展性好。
4.2. 缺点
每新增一个功能,就要加一个实现类,并需要修改工厂类的出口方法。这无疑会增加系统的复杂度,不利于维护。