【设计模式系列】抽象工厂模式

一、什么是抽象工厂模式

抽象工厂模式(Abstract Factory Pattern)是一种创建型设计模式,++它提供了一个接口,用于创建一系列相关或相互依赖的对象,而无需指定它们具体的类++。这种模式允许客户端使用抽象的接口来创建一组相关产品,而不需要知道或关心实际生产出的具体产品是什么,从而实现客户端与具体产品的解耦。

二、抽象工厂模式的角色

  1. 抽象产品族(Abstract Product)

    • 这是一组相关的抽象类或接口,它们定义了可能被创建的对象的公共接口。
    • 这些抽象产品通常包含在一个或多个产品等级结构中,每个产品等级结构代表一类产品。
  2. 具体产品(Concrete Product)

    • 这些是抽象产品的实现类,它们提供了抽象产品接口的具体实现。
    • 每个具体产品都是抽象产品接口的具体类,代表一个具体的对象。
  3. 抽象工厂(Abstract Factory)

    • 这是一个接口,它声明了一组方法,用于创建一系列相关的抽象产品。
    • 它不实现这些方法,而是将实现推迟到子类中。
    • 抽象工厂定义了可以被创建的产品集合,但不定义具体如何创建这些产品。
  4. 具体工厂(Concrete Factory)

    • 这些类实现了抽象工厂接口,并提供了具体工厂方法来创建具体的产品对象。
    • 每个具体工厂都对应一个产品族,它负责创建该族中的具体产品。
    • 具体工厂封装了具体产品的创建逻辑,客户端可以通过具体工厂来创建所需的产品,而无需知道具体的创建细节。

三、抽象工厂模式的典型应用场景

  1. 多系列产品创建: 当一个系统需要创建多个系列的相关产品,并且这些产品之间存在相互依赖关系时,使用抽象工厂模式可以确保客户端始终使用同一个系列的产品。

四、抽象工厂模式在Calendar中的应用

在抽象工厂模式中,Calendar 类可以被视为一个抽象工厂,它提供了创建各种具体日历实例的接口。GregorianCalendarBuddhistCalendarCalendar 类的具体实现,代表不同的日历系统。下面详细展开 Calendar 在抽象工厂模式中的应用,并给出包含 BuddhistCalendarGregorianCalendar 的代码示例。

概念解释

  • 抽象产品族(Abstract Product Family):在日历系统中,这可以是日期和时间的表示方式,包括年、月、日等。

  • 抽象产品(Abstract Product)Calendar 类本身,它定义了所有具体日历类必须实现的接口,如 getTime()setTime(Date date)get(int field) 等。

  • 具体产品(Concrete Product)GregorianCalendarBuddhistCalendar 是具体的产品类,它们实现了 Calendar 抽象类,并提供了特定日历系统的具体实现。

  • 抽象工厂(Abstract Factory)Calendar 类也可以被视为一个抽象工厂,因为它的静态方法 getInstance() 可以根据传入的 Locale 参数返回不同的 Calendar 实例。

  • 具体工厂(Concrete Factory) :在这个模式中,具体工厂由 JDK 内部实现,它根据 Locale 参数决定实例化 GregorianCalendar 还是 BuddhistCalendar

java 复制代码
//抽象工厂类
public abstract class Calendar {
    public static class Builder {
        public Builder setDate(int year, int month, int dayOfMonth) {
            return setFields(YEAR, year, MONTH, month, DAY_OF_MONTH, dayOfMonth);
        }

        public Builder setTimeOfDay(int hourOfDay, int minute, int second) {
            return setTimeOfDay(hourOfDay, minute, second, 0);
        }
    }

    public static Calendar getInstance()
    {
        return createCalendar(TimeZone.getDefault(), Locale.getDefault(Locale.Category.FORMAT));
    }

    public int getWeeksInWeekYear() {
        throw new UnsupportedOperationException();
    }
}

//具体工厂类
public class GregorianCalendar extends Calendar {
    @Override
    public int getWeeksInWeekYear() {
        GregorianCalendar gc = getNormalizedCalendar();
        int weekYear = gc.getWeekYear();
        if (weekYear == gc.internalGet(YEAR)) {
            return gc.getActualMaximum(WEEK_OF_YEAR);
        }

        // Use the 2nd week for calculating the max of WEEK_OF_YEAR
        if (gc == this) {
            gc = (GregorianCalendar) gc.clone();
        }
        gc.setWeekDate(weekYear, 2, internalGet(DAY_OF_WEEK));
        return gc.getActualMaximum(WEEK_OF_YEAR);
    }
}

//具体工厂类
public class BuddhistCalendar extends GregorianCalendar {

}

// 客户端
public class CalendarAbstractFactoryDemo {

    public static void main(String[] args) {
        // 创建一个默认的 GregorianCalendar 实例
        Calendar defaultCalendar = Calendar.getInstance();
        printCalendarInfo(defaultCalendar, "Default Calendar");

        // 创建一个 BuddhistCalendar 实例,用于泰国
        Locale thailandLocale = new Locale("th", "TH");
        Calendar thaiCalendar = Calendar.getInstance(thailandLocale);
        printCalendarInfo(thaiCalendar, "Thai Buddhist Calendar");
    }

    private static void printCalendarInfo(Calendar calendar, String calendarType) {
        // 设置日期
        calendar.setTime(new Date());
        System.out.println(calendarType + " - Year: " + calendar.get(Calendar.YEAR));
        System.out.println(calendarType + " - Month: " + calendar.getDisplayName(Calendar.MONTH, Calendar.LONG, Locale.ENGLISH));
        System.out.println(calendarType + " - Day: " + calendar.get(Calendar.DAY_OF_MONTH));
        System.out.println();
    }
}

在这个示例中:

  • Calendar.getInstance() 方法根据提供的 Locale 参数决定创建哪种具体的 Calendar 实例。如果没有指定 Locale,它通常会创建一个 GregorianCalendar 实例,这是大多数地区的默认日历系统。
  • 当我们传递泰国的 Locale 对象给 Calendar.getInstance() 方法时,它返回一个 BuddhistCalendar 实例,这是泰国使用的日历系统。
  • printCalendarInfo() 方法打印日历的详细信息,包括年、月、日。它展示了如何使用 Calendar 实例来获取日期信息。

这个例子展示了 Calendar 类如何作为一个抽象工厂,根据不同的 Locale 参数创建不同的日历实例。这种方式使得客户端代码能够灵活地根据不同的需求创建适当的日历对象,而不需要了解具体的日历实现细节。这种设计符合抽象工厂模式的原则,提供了一个创建一系列相关或相互依赖对象的接口,而不需要指定它们具体的类。

五、简单工厂模式与复杂工厂模式的区别

简单工厂模式和抽象工厂模式都是创建型设计模式,用于创建对象,但它们在解决问题的范围和方式上存在明显差异:

简单工厂模式

  • 解决问题的范围:简单工厂模式主要用于创建单一类型的产品。它适用于场景中对象的创建逻辑相对简单,或者需要创建的对象种类较少的情况。
  • 核心思想:简单工厂模式通过一个工厂类包含一个或多个方法,根据传入的参数来决定创建并返回哪种具体产品的实例。

抽象工厂模式

  • 解决问题的范围:抽象工厂模式用于创建多个产品族中相关或相互依赖的产品对象。它适用于场景中需要创建一系列相关或相互依赖的产品,且这些产品属于不同的产品等级结构。
  • 核心思想:抽象工厂模式定义了一个接口,用于创建一系列相关的产品,而不需要指定它们的具体类。具体工厂类实现了这个接口,并提供了创建具体产品的方法。
相关推荐
面朝大海,春不暖,花不开12 分钟前
自定义Spring Boot Starter的全面指南
java·spring boot·后端
得过且过的勇者y12 分钟前
Java安全点safepoint
java
夜晚回家1 小时前
「Java基本语法」代码格式与注释规范
java·开发语言
斯普信云原生组1 小时前
Docker构建自定义的镜像
java·spring cloud·docker
wangjinjin1801 小时前
使用 IntelliJ IDEA 安装通义灵码(TONGYI Lingma)插件,进行后端 Java Spring Boot 项目的用户用例生成及常见问题处理
java·spring boot·intellij-idea
wtg44521 小时前
使用 Rest-Assured 和 TestNG 进行购物车功能的 API 自动化测试
java
白宇横流学长1 小时前
基于SpringBoot实现的大创管理系统设计与实现【源码+文档】
java·spring boot·后端
fat house cat_2 小时前
【redis】线程IO模型
java·redis
stein_java3 小时前
springMVC-10验证及国际化
java·spring
weixin_478689763 小时前
C++ 对 C 的兼容性
java·c语言·c++