设计模式-简单工厂模式
转载请注明出处:https://www.cnblogs.com/wenjunwei/p/9802128.html
定义
简单工厂模式(Simple Factory Pattern):定义一个工厂类,它可以根据参数的不同返回不同类的实例,被创建的实例通常都具有共同的父类。因为在简单工厂模式中用于创建实例的方法是静态(static)方法,因此简单工厂模式又被称为静态工厂方法(Static Factory Method)模式,它属于类创建型模式。
- 简单工厂模式提供了专门的工厂类用于创建对象,将对象的创建和对象的使用分离开,它作为一种最简单的工厂模式在软件开发中得到了较为广泛的应用;
- 简单工厂模式是工厂方法模式的“小弟”,它不属于23种设计模式,但在软件开发中应用也较为频繁,通常将它作为学习其他工厂模式的入门;
- 简单工厂模式的要点在于:当你需要什么,只需要传入一个正确的参数,就可以获取你所需要的对象,而无须知道其创建细节。
简介
应用实例
- 您需要一辆汽车,可以直接从工厂里面提货,而不用去管这辆汽车是怎么做出来的,以及这个汽车里面的具体实现;
- Hibernate 换数据库只需换方言和驱动就可以。
使用场景
- 工厂类负责创建的对象比较少,由于创建的对象较少,不会造成工厂方法中的业务逻辑太过复杂;
- 客户端只知道传入工厂类的参数,对于如何创建对象并不关心。
实现:图标库设计
公司欲基于Java语言开发一套图表库,该图表库可以为应用系统提供各种不同外观的图表,例如柱状图、饼状图、折线图等。设计人员希望为应用系统开发人员提供一套灵活易用的图表库,而且可以较为方便地对图表库进行扩展,以便能够在将来增加一些新类型的图表。
方案一
class Chart { private String type; //图表类型 public Chart(String type) { this.type = type; if (type.equalsIgnoreCase("histogram")) { System.out.println("初始化柱状图!"); } else if (type.equalsIgnoreCase("pie")) { System.out.println("初始化饼状图!"); } else if (type.equalsIgnoreCase("line")) { System.out.println("初始化折线图!"); } } public void display() { if (this.type.equalsIgnoreCase("histogram")) { System.out.println("显示柱状图!"); } else if (this.type.equalsIgnoreCase("pie")) { System.out.println("显示饼状图!"); } else if (this.type.equalsIgnoreCase("line")) { System.out.println("显示折线图!"); } } }
分析以上代码:
- 代码“if else”代码块很多,代码冗长,如果再多几种类型,阅读、维护、测试难度就会越复杂。
- 代码集中,职责过重,违反了“单一职责原则”,不利于重用、维护和扩展。
- 在扩展的时候必须修改Chart类,违反了“开闭原则”。
- 客户端只能通过new关键字来直接创建Chart对象,Chart类与客户端类耦合度较高,对象的创建和使用无法分离。
- 客户端在创建Chart对象之前可能还需要进行大量初始化设置,例如设置柱状图的颜色、高度等,如果在Chart类的构造函数中没有提供一个默认设置,那就只能由客户端来完成初始设置,这些代码在每次创建Chart对象时都会出现,导致代码的重复。
方案二(使用简单工厂模式)
为了将Chart类的职责分离,同时将Chart对象的创建和使用分离,重新对代码进行了重构。
创建图表接口
public interface Chart { /** * 展示图表 */ void display(); }
创建图表工厂
public class ChartFactory { //静态工厂方法 public static Chart getChart(String type) { Chart chart = null; if (type.equalsIgnoreCase("histogram")) { chart = new HistogramChart(); System.out.println("初始化设置柱状图!"); } else if (type.equalsIgnoreCase("pie")) { chart = new PieChart(); System.out.println("初始化设置饼状图!"); } else if (type.equalsIgnoreCase("line")) { chart = new LineChart(); System.out.println("初始化设置折线图!"); } return chart; } }
创建实现类
public class HistogramChart implements Chart { public HistogramChart() { System.out.println("创建柱状图!"); } public void display() { System.out.println("显示柱状图!"); } }
public class LineChart implements Chart { public LineChart() { System.out.println("创建折线图!"); } public void display() { System.out.println("显示折线图!"); } }
public class PieChart implements Chart { public PieChart() { System.out.println("创建饼状图!"); } public void display() { System.out.println("显示饼状图!"); } }
测试代码
public class Main { public final static String CHART_HISTOGRAM = "histogram"; public final static String CHART_PIE = "pie"; public final static String CHART_LINE = "line"; public static void main(String[] args) { //通过静态工厂方法创建产品 Chart chartHistogram = ChartFactory.getChart(CHART_HISTOGRAM); chartHistogram.display(); Chart chartPie = ChartFactory.getChart(CHART_PIE); chartPie.display(); Chart chartLine = ChartFactory.getChart(CHART_LINE); chartLine.display(); } }
输出如下
创建柱状图!
初始化设置柱状图!
显示柱状图!
创建饼状图!
初始化设置饼状图!
显示饼状图!
创建折线图!
初始化设置折线图!
显示折线图!
分析以上代码:在测试类中,我们使用工厂类的静态方法来创建对象,如果需要更换其他图表,只需要修改参数即可。
改进:上述代码还存在一个问题,在每次客户端更换静态工厂中的参数时,客户端代码都需要重新编译,对客户端而言,违反了“开闭原则”。
怎么能在修改参数时不需要修改客户端代码呢?
我们只需要参数放入配置文件即可。如果需要修改具体图表参数,只需要修改配置文件,无需修改任何源代码,符合“开闭原则”。
总结
优点
- 一个调用者想创建一个对象,只要知道其名称就可以了;
- 扩展性高,如果想增加一个产品,只要扩展一个工厂类就可以;
- 屏蔽产品的具体实现,调用者只关心产品的接口;
- 实现了对象创建和使用分离;
- 通过引入配置文件,可以在不修改任何客户端代码的情况下更换和增加新的具体产品类,在一定程度上提高了系统的灵活性。
缺点
- 由于工厂类集中了所有产品的创建逻辑,职责过重,一旦不能正常工作,整个系统都要受到影响;
- 每次增加一个产品时,都需要增加一个具体类和对象实现工厂,使得系统中类的个数成倍增加,在一定程度上增加了系统的复杂度,同时也增加了系统具体类的依赖;
- 简单工厂模式由于使用了静态工厂方法,造成工厂角色无法形成基于继承的等级结构。
感谢您的阅读,如果您觉得阅读本文对您有帮助,请点一下“推荐”按钮。本文欢迎各位转载,但是转载文章之后必须在文章开头给出原文链接。