【设计模式笔记10】:简单工厂模式示例

文章目录

简单工厂模式示例

示例1:电视机工厂

接续上一节的电视机场景,我们来看一个完整的代码实现。

  • 代码实现:

    java 复制代码
    // 角色1: 抽象产品 (Product)
    // 定义电视机的通用行为:播放
    interface Product {
        public void play(); 
    }
    
    // 角色2: 具体产品A (ConcreteProductA)
    // 海尔电视机
    class ConcreteProductA implements Product {
        @Override
        public void play() {
            System.out.println("海尔电视机播放中......");
        }
    }
    
    // 角色2: 具体产品B (ConcreteProductB)
    // 海信电视机
    class ConcreteProductB implements Product {
        @Override
        public 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("对不起,暂不能生产该品牌电视机!");
            }
        }
    }
  • 客户端调用:

    java 复制代码
    // 测试类 (客户端)
    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类中。
    java 复制代码
    // 违反单一职责和开闭原则的设计
    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),根据传入的类型字符串创建并返回具体的图表对象。
  • 重构后代码实现:

    java 复制代码
    // 抽象产品: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;
        }
    }
  • 客户端调用:

    java 复制代码
    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()
    java 复制代码
    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开始,需要+1
            System.out.println("月: " + (cal.get(Calendar.MONTH) + 1)); 
            System.out.println("日: " + cal.get(Calendar.DAY_OF_MONTH));
        }
    }
  • 内部机制:

    • getInstance() 方法会根据系统当前的区域设置(Locale)和时区(TimeZone)等信息,在内部决定具体创建并返回哪一个Calendar的子类实例(例如,在大多数情况下是GregorianCalendar)。
    • 这样,客户端代码完全不需要关心底层具体使用的是哪种日历实现,只需要与Calendar这个抽象类进行交互即可。这极大地提高了代码的灵活性和可维护性。
相关推荐
n***i9512 小时前
Java NIO文件操作
java·开发语言·nio
笃行客从不躺平13 小时前
接口幂等性(Idempotency)
java
Hero | 柒13 小时前
JAVA反射机制
java·spring·反射
j***630813 小时前
Springboot项目中线程池使用整理
java·spring boot·后端
likuolei14 小时前
Eclipse 创建 Java 接口
java·数据库·eclipse
q***547514 小时前
Spring Boot 经典九设计模式全览
java·spring boot·设计模式
a***560614 小时前
Spring Boot接收参数的19种方式
java·spring boot·后端
z***751514 小时前
SpringBoot集成MQTT客户端
java·spring boot·后端
q***697714 小时前
java进阶1——JVM
java·开发语言·jvm
码力码力我爱你14 小时前
C++静态变量依赖关系
java·jvm·c++