什么是工厂模式?
所谓工厂模式,简单的来说,就是自己不再主动创建对象,而是让工厂来帮我们创建对象。
真实场景
统计图表需求:客户需要根据用户的性别、年龄段、居住地信息做一个可切换的统计数据。
如何使用?
-
简单实现,拿到这个需求,是不是so easy?开写:
package com.test.factory; public class CountTest { public static void main(String []args) { CountTest test = new CountTest(); test.count("性别"); test.count("年龄段"); test.count("居住地"); } public void count(String type) { if(type.equals("性别")) { System.out.println("我是根据<性别>产生的统计数据"); return; } if(type.equals("年龄段")) { System.out.println("我是根据<年龄段>产生的统计数据"); return; } if(type.equals("居住地")) { System.out.println("我是根据<居住地>产生的统计数据"); return; } } }
分析代码利弊
-
优势:快速,写完上述代码可能你就花了2分钟。
-
劣势:扩展性不强,当客户方再提出需要根据证件类型统计等需求呢!当其中一个统计逻辑发生修改时,我们都得去修改count方法,这时候我们就应该思考当应用的需求改变时,在不修改原有代码的前提下,如何扩展模块的功能使其满足新的需求。
使用场景
扩展性要求不高的功能模块 -
-
简单工厂实现(又称静态工厂),顾名思义有一个工厂类,且工厂类里面是有静态方法,静态方法应该是用来创建一系列产品的(性别统计、年龄段统计、居住地),这些产品都需要进行统计的操作,如果要创建的产品不多,只要一个工厂类就可以完成,这种模式叫“简单工厂模式”。
package com.test.factory; public class StaticFactoryTest { public static void main(String []args) { CountFactory.create("性别").count(); CountFactory.create("年龄段").count(); CountFactory.create("居住地").count(); CountFactory.create("证件类型").count(); } } //抽象接口 interface CountProduct { //产品行为 void count(); } //实现类 class 性别 implements CountProduct{ @Override public void count() { System.out.println("我是根据<性别>产生的统计数据"); } } //实现类 class 年龄段 implements CountProduct{ @Override public void count() { System.out.println("我是根据<年龄段>产生的统计数据"); } } //实现类 class 居住地 implements CountProduct{ @Override public void count() { System.out.println("我是根据<居住地>产生的统计数据"); } } //实现类 class 证件类型 implements CountProduct{ @Override public void count() { System.out.println("我是根据<证件类型>产生的统计数据"); } } //简单工厂 class CountFactory { //工厂方法 public static CountProduct create(String type){ CountProduct product = null; switch (type) { case "性别" : product = new 性别(); break; case "年龄段" : product = new 年龄段(); break; case "居住地" : product = new 居住地(); break; case "证件类型" : product = new 证件类型(); break; } return product; } }
分析代码利弊
-
优势:有了一定的扩展性,并且将产品的创建和业务逻辑给分离开了。
-
劣势:一旦添加新产品就不得不修改工厂逻辑,同样破坏了软件设计的“开闭原则”。
使用场景
1.工厂类负责创建的对象比较少:由于创建的对象较少,不会造成工厂方法中的业务逻辑太过复杂。
2.实际生产中,我们也可以修改工厂中的create方法通过配置文件的方式去配置type和产品的关系,这样我们就可以不同改变创建产品的方法了。
3.静态工厂也可以根据我们的实际使用进行变形,我们可以在工厂类中有多个创建产品的方法,去创建不同的产品,这样我们也就不需要条件去判断了,符合软件设计的“单一职责原则”。 -
-
工厂方法实现,就是我们常说的工厂模式,静态工厂中添加新的产品时候,获取产品的工厂逻辑需要修改,来看下我们怎么通过工厂方法的方式避免吧!
package com.test.factory; public class MethodFactoryTest { public static void main(String []args) { CountFactory 性别factory = new 性别Factory(); 性别factory.createProduct().count(); CountFactory 年龄段factory = new 年龄段Factory(); 年龄段factory.createProduct().count(); } } //产品抽象 interface CountProduct { void count(); } //真实产品 class 性别 implements com.test.factory.CountProduct { @Override public void count() { System.out.println("我是根据<性别>产生的统计数据"); } } //真实产品 class 年龄段 implements com.test.factory.CountProduct { @Override public void count() { System.out.println("我是根据<年龄段>产生的统计数据"); } } //工厂抽象 interface CountFactory { CountProduct createProduct(); } //具体工厂 class 性别Factory implements CountFactory { @Override public CountProduct createProduct() { return (CountProduct) new 性别(); } } //具体工厂 class 年龄段Factory implements CountFactory { @Override public CountProduct createProduct() { return (CountProduct) new 年龄段(); } }
分析代码利弊
1.优势:使用者只需知道创建产品的工厂名,而不知道具体的产品名,添加新的产品的时候,只需添加相应产品类和工厂类,不影响其他代码。
2.劣势:代码复杂度提升,对于系统中存在不同的产品树没法解决(抽象工厂模式解决)。
使用场景
扩展性要求高的功能模块
为什么使用工厂模式?
在实际需求中许多功能模块随着迭代的过程越来越细化。工厂模式能做到软件对象的生产和使用相分离,在满足“开闭原则”的前提下,可以满足客户随意增删或改变对软件相关对象的使用,从而提高代码的可维护性上,可扩展性。
总结
文章至此,有没有感觉工厂模式有点熟悉,是的,我们常用的spring框架中就有工厂模式的应用,在Spring中有两个最基本的工厂,BeanFactory和ApplicationContext。BeanFactory是Spring框架的基础设施,面向的是Spring本身,也就是用于创建Spring扩展的其他内容,如Spring Security、Spring JDBC等,而ApplicationContext这个工厂是面向开发者的,也就是应用上下文——配置文件等,开发者能够使用这个工厂实现自己的功能。
工厂模式的思想正好契合Spring IOC的设计思想:某一接口的具体实现类的选择控制权从调用类中移除,转而交给第三方决定,即借由Spring的Bean配置来实现控制,这同样也是工厂模式的思想。