【设计模式笔记10】:简单工厂模式示例
文章目录
- 简单工厂模式示例
- 示例1:电视机工厂
- 示例2:图表库工厂
- 在JDK中的应用:`java.util.Calendar`
简单工厂模式示例
示例1:电视机工厂
接续上一节的电视机场景,我们来看一个完整的代码实现。
-
代码实现:
// 角色1: 抽象产品 (Product) // 定义电视机的通用行为:播放 interface Product {public void play(); }// 角色2: 具体产品A (ConcreteProductA) // 海尔电视机 class ConcreteProductA implements Product {@Overridepublic void play() {System.out.println("海尔电视机播放中......");} }// 角色2: 具体产品B (ConcreteProductB) // 海信电视机 class ConcreteProductB implements Product {@Overridepublic void play() {System.out.println("海信电视机播放中......");} }// 角色3: 工厂类 (Factory) class Factory {// 提供生产产品的静态方法public static Product produce(String brand) throws Exception {if (brand.equalsIgnoreCase("Haier")) {System.out.println("电视机工厂生产海尔电视机!");return new ConcreteProductA();} else if (brand.equalsIgnoreCase("Hisense")) {System.out.println("电视机工厂生产海信电视机!");return new ConcreteProductB();} else {// 对于无法生产的品牌,抛出异常throw new Exception("对不起,暂不能生产该品牌电视机!");}} } -
客户端调用:
// 测试类 (客户端) public class SimpleFactory {public static void main(String[] args) {try {// 客户端向工厂请求产品,只需要提供品牌名Product tv = Factory.produce("Haier");// 客户端直接使用产品,无需关心其具体类型和创建过程tv.play();// 更换品牌也只需修改参数// Product tv2 = Factory.produce("Hisense");// tv2.play();} catch (Exception e) {System.out.println(e.getMessage());}} } -
运行效果:
电视机工厂生产海尔电视机! 海尔电视机播放中......
示例2:图表库工厂
-
背景需求:
- Sunny软件公司要开发一套图表库,提供柱状图、饼状图、折线图等不同外观的图表。
- 设计目标是为应用系统开发者提供一套灵活易用的图表库,并且可以较为方便地对图表库进行扩展,以便将来增加新类型的图表。
-
初始设计 (反面教材):
- 最初,可能将所有图表的创建和显示逻辑都耦合在一个
Chart类中。
// 违反单一职责和开闭原则的设计 public class Chart {private String type; // 图表类型// 构造函数中根据类型进行不同的初始化public Chart(Object[][] data, String type) {this.type = type;if (type.equalsIgnoreCase("histogram")) {// 初始化柱状图} else if (type.equalsIgnoreCase("pie")) {// 初始化饼状图} else if (type.equalsIgnoreCase("line")) {// 初始化折线图}}// 显示方法中根据类型进行不同的显示public void display() {if (this.type.equalsIgnoreCase("histogram")) {// 显示柱状图} else if (this.type.equalsIgnoreCase("pie")) {// 显示饼状图} else if (this.type.equalsIgnoreCase("line")) {// 显示折线图}} }- 问题分析: 这个
Chart类职责过重,既负责创建(初始化)又负责显示。而且,每当需要增加一种新的图表类型时,都必须修改这个类的构造函数和display方法,违反了开闭原则。
- 最初,可能将所有图表的创建和显示逻辑都耦合在一个
-
使用简单工厂模式重构:
- 模式角色分析:
- 抽象产品 (Product):
Chart接口,定义所有图表都必须具备的display()方法。 - 具体产品 (ConcreteProduct):
HistogramChart,PieChart,LineChart等类,分别实现Chart接口,负责各自图表的具体显示逻辑。 - 工厂 (Factory):
ChartFactory类,提供一个静态方法getChart(String type),根据传入的类型字符串创建并返回具体的图表对象。
- 抽象产品 (Product):
- 模式角色分析:
-
重构后代码实现:
// 抽象产品:Chart接口 public interface Chart {public void display(); }// 具体产品:HistogramChart, PieChart, LineChart 类(代码略,各自实现display方法)// 工厂类:ChartFactory 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;} } -
客户端调用:
class Client {public static void main(String[] args) {Chart chart;// 客户端通过工厂获取实例,实现了创建和使用的分离chart = ChartFactory.getChart("line"); chart.display(); // 调用产品的功能} } -
运行效果:
初始化设置折线图! 显示折线图!
在JDK中的应用:java.util.Calendar
简单工厂模式(静态工厂方法)在Java的JDK源码中也有广泛应用。一个典型的例子就是java.util.Calendar类。
-
源码分析:
- 我们获取
Calendar实例时,并不是通过new Calendar()(Calendar是抽象类,无法直接new),而是通过调用它的静态方法Calendar.getInstance()。
import java.util.Calendar;public class Factory {public static void main(String[] args) {// getInstance() 就是一个静态工厂方法Calendar cal = Calendar.getInstance();System.out.println("年: " + cal.get(Calendar.YEAR));// 月份从0开始,需要+1System.out.println("月: " + (cal.get(Calendar.MONTH) + 1)); System.out.println("日: " + cal.get(Calendar.DAY_OF_MONTH));} } - 我们获取
-
内部机制:
getInstance()方法会根据系统当前的区域设置(Locale)和时区(TimeZone)等信息,在内部决定具体创建并返回哪一个Calendar的子类实例(例如,在大多数情况下是GregorianCalendar)。- 这样,客户端代码完全不需要关心底层具体使用的是哪种日历实现,只需要与
Calendar这个抽象类进行交互即可。这极大地提高了代码的灵活性和可维护性。
