Factory Method工厂方法模式(Java代码实现)——创建型模式

简介: Factory Method工厂方法模式(Java代码实现)——创建型模式

在本人所编写的关于23种设计模式的文章中,前言基本上都是一样的,读者可以从章节2开始阅读,本篇是关于创建型模式中工厂方法模式(Factory Method Pattern)的详解。

1.前言

根据Design Patterns - Elements of Reusable Object-Oriented Software(中文译名:设计模式 - 可复用面向对象软件的基础) 一书,四位作者把设计模式分为三大类,分别如下:

1.创建型模式
这些设计模式提供了一种在创建对象的同时隐藏创建逻辑的方式,而不是使用 new 运算符直接实例化对象。这使得程序在判断针对某个给定实例需要创建哪些对象时更加灵活。

  • 单例模式(Singleton Pattern)
  • 抽象工厂模式(Abstract Factory Pattern)
  • 工厂方法模式(Factory Method Pattern)
  • 建造者模式(Builder Pattern)
  • 原型模式(Prototype Pattern)

2.结构型模式
这些设计模式关注类和对象的组合。继承的概念被用来组合接口和定义组合对象获得新功能的方式。

  • 适配器模式(Adapter Pattern)
  • 桥接模式(Bridge Pattern)
  • 组合模式(Composite Pattern)
  • 装饰器模式(Decorator Pattern)
  • 外观模式(Facade Pattern)
  • 享元模式(Flyweight Pattern)
  • 代理模式(Proxy Pattern)

3.行为型模式
这些设计模式特别关注对象之间的通信。

  • 责任链模式(Chain of Responsibility Pattern)
  • 命令模式(Command Pattern)
  • 解释器模式(Interpreter Pattern)
  • 迭代器模式(Iterator Pattern)
  • 中介者模式(Mediator Pattern)
  • 备忘录模式(Memento Pattern)
  • 观察者模式(Observer Pattern)
  • 状态模式(State Pattern)
  • 策略模式(Strategy Pattern)
  • 模板模式(Template Pattern)
  • 访问者模式(Visitor Pattern)

本篇是关于创建型模式中工厂方法模式(Factory Method Pattern)的详解。

2.工厂方法模式(Factory Method Pattern)

2.1.意图

定义一个用于创建对象的接口,让子类决定实例化哪一个类。Factory Method使一个类的实例化延迟到其子类。

2.2UML类图

在工厂模式中,我们在创建对象时不会对使用端暴露创建逻辑,并且是通过使用一个共同的接口(下图中TeaFactory)来指向新创建的对象,如下(以现在热门的奶茶为例):
在这里插入图片描述

2.3.Java代码具体实现

2.3.1包结构如下:

在这里插入图片描述

2.3.2tea包

public interface Tea {
    
    void make();
}
public class BlackTea implements Tea {
     


    @Override
    public void make() {
     
        System.out.println("make the black tea!");
    }
}
public class GreenTea implements Tea {
      
    @Override
    public void make() {
      
        System.out.println("make the green tea!");
    }
}
public class MilkTea implements Tea {
       
    @Override
    public void make() {
       
        System.out.println("make the milk tea!");
    }
}

2.3.3factory包

/** * @Author: YuShiwen * @Date: 2022/2/3 10:43 PM * @Version: 1.0 */
public class TeaFactory {
        
    public Tea getTea(String tea) {
        
        if ("blackTea".equalsIgnoreCase(tea)) {
        
            return new BlackTea();
        } else if ("greenTea".equalsIgnoreCase(tea)) {
        
            return new GreenTea();
        } else if ("milkTea".equalsIgnoreCase(tea)) {
        
            return new MilkTea();
        } else {
        
            throw new RuntimeException("其他茶品暂不支持!");
        }
    }
}

2.3.4main包

public class CustomerDemo {
          public static void main(String[] args) {
          new TeaFactory().getTea("milktea").make(); new TeaFactory().getTea("blacktea").make(); } } 

2.3.5运行结果

在这里插入图片描述

2.4.优缺点

优点:
1、一个调用者想创建一个对象,只要知道其名称就可以了。
2、扩展性高,如果想增加一个产品,只要扩展一个工厂类就可以。
3、屏蔽产品的具体实现,调用者只关心产品的接口。

缺点:
每次增加一个产品时,都需要增加一个具体类和对象实现工厂,使得系统中类的个数成倍增加,在一定程度上增加了系统的复杂度,同时也增加了系统具体类的依赖。

建议:
作为一种创建类模式,在任何需要生成复杂对象的地方,都可以使用工厂方法模式。有一点需要注意的地方就是复杂对象适合使用工厂模式,而简单对象,特别是只需要通过 new 就可以完成创建的对象,无需使用工厂模式。如果使用工厂模式,就需要引入一个工厂类,会增加系统的复杂度。

2.5在源码中的应用

2.5.1Integer.valueOf()方法

Integer它提供了静态方法valueOf()来创建Integer。那么这种方式和直接写new Integer(3)有何区别呢?我们观察valueOf()方法:
它的好处在于,valueOf()内部可能会使用new创建一个新的Integer实例,但也可能直接返回一个缓存的Integer实例。Integer默认的是[-128, 127]的缓存范围,我们查看源码的时候也发现了,其中的low的下限是最开始的时候就固定死了的 final int low = -128;而其中的high虽然是设置了final int的,但是最初的时候,是还没有赋值的;所以我们可以通过设置java 的时候的参数来配置运行时的参数:
java -D java.lang.Integer.IntegerCache.high=1024 TestAutoBoxCache
在这里插入图片描述

对于调用方来说,没必要知道Integer创建的细节。
工厂方法可以隐藏创建产品的细节,且不一定每次都会真正创建产品,完全可以返回缓存的产品,从而提升速度并减少内存消耗。

2.5.2List.of()方法

List.of()是Java9提供的方法,这个静态工厂方法接收可变参数,然后返回List接口。相较于Arrays.asList()方法,原数组修改对Arrays.asList生成的List有影响,对List.of 生成的List无影响。调用方获取的产品总是List接口,而且并不关心它的实际类型。即使调用方知道List产品的实际类型是java.util.ImmutableCollections$ListN,也不要去强制转型为子类,因为静态工厂方法List.of()保证返回List,但也完全可以修改为返回java.util.ArrayList。这就是里氏替换原则:返回实现接口的任意子类都可以满足该方法的要求,且不影响调用方。
在这里插入图片描述
在这里插入图片描述

2.5.3MessageDigest.getInstance()方法

在这里插入图片描述

对于MessageDigest.getInstance()方法也是如此,比如我们可以通过MessageDigest.getInstance("MD5");来获取MD5算法。

并且在Effective Java一书中,第二章第一条就是用静态工厂方法代替构造器

c514bba66c334ed49e2b9eefe8ac17be.png已完结,于2022年大年初四凌晨。
相关文章
|
9天前
|
JavaScript NoSQL Java
接替此文【下篇-服务端+后台管理】优雅草蜻蜓z系统JAVA版暗影版为例-【蜻蜓z系列通用】-2025年全新项目整合搭建方式-这是独立吃透代码以后首次改变-独立PC版本vue版搭建教程-优雅草卓伊凡
接替此文【下篇-服务端+后台管理】优雅草蜻蜓z系统JAVA版暗影版为例-【蜻蜓z系列通用】-2025年全新项目整合搭建方式-这是独立吃透代码以后首次改变-独立PC版本vue版搭建教程-优雅草卓伊凡
155 96
接替此文【下篇-服务端+后台管理】优雅草蜻蜓z系统JAVA版暗影版为例-【蜻蜓z系列通用】-2025年全新项目整合搭建方式-这是独立吃透代码以后首次改变-独立PC版本vue版搭建教程-优雅草卓伊凡
|
1月前
|
SQL Java 数据库连接
如何在 Java 代码中使用 JSqlParser 解析复杂的 SQL 语句?
大家好,我是 V 哥。JSqlParser 是一个用于解析 SQL 语句的 Java 库,可将 SQL 解析为 Java 对象树,支持多种 SQL 类型(如 `SELECT`、`INSERT` 等)。它适用于 SQL 分析、修改、生成和验证等场景。通过 Maven 或 Gradle 安装后,可以方便地在 Java 代码中使用。
285 11
|
1月前
|
JSON Java 数据挖掘
利用 Java 代码获取淘宝关键字 API 接口
在数字化商业时代,精准把握市场动态与消费者需求是企业成功的关键。淘宝作为中国最大的电商平台之一,其海量数据中蕴含丰富的商业洞察。本文介绍如何通过Java代码高效、合规地获取淘宝关键字API接口数据,帮助商家优化产品布局、制定营销策略。主要内容包括: 1. **淘宝关键字API的价值**:洞察用户需求、优化产品标题与详情、制定营销策略。 2. **获取API接口的步骤**:注册账号、申请权限、搭建Java开发环境、编写调用代码、解析响应数据。 3. **注意事项**:遵守法律法规与平台规则,处理API调用限制。 通过这些步骤,商家可以在激烈的市场竞争中脱颖而出。
|
2月前
|
安全 Java 编译器
深入理解Java中synchronized三种使用方式:助您写出线程安全的代码
`synchronized` 是 Java 中的关键字,用于实现线程同步,确保多个线程互斥访问共享资源。它通过内置的监视器锁机制,防止多个线程同时执行被 `synchronized` 修饰的方法或代码块。`synchronized` 可以修饰非静态方法、静态方法和代码块,分别锁定实例对象、类对象或指定的对象。其底层原理基于 JVM 的指令和对象的监视器,JDK 1.6 后引入了偏向锁、轻量级锁等优化措施,提高了性能。
78 3
|
5天前
|
Java 程序员 开发者
Java社招面试题:一个线程运行时发生异常会怎样?
大家好,我是小米。今天分享一个经典的 Java 面试题:线程运行时发生异常,程序会怎样处理?此问题考察 Java 线程和异常处理机制的理解。线程发生异常,默认会导致线程终止,但可以通过 try-catch 捕获并处理,避免影响其他线程。未捕获的异常可通过 Thread.UncaughtExceptionHandler 处理。线程池中的异常会被自动处理,不影响任务执行。希望这篇文章能帮助你深入理解 Java 线程异常处理机制,为面试做好准备。如果你觉得有帮助,欢迎收藏、转发!
53 14
|
8天前
|
安全 Java 程序员
Java 面试必问!线程构造方法和静态块的执行线程到底是谁?
大家好,我是小米。今天聊聊Java多线程面试题:线程类的构造方法和静态块是由哪个线程调用的?构造方法由创建线程实例的主线程调用,静态块在类加载时由主线程调用。理解这些细节有助于掌握Java多线程机制。下期再见! 简介: 本文通过一个常见的Java多线程面试题,详细讲解了线程类的构造方法和静态块是由哪个线程调用的。构造方法由创建线程实例的主线程调用,静态块在类加载时由主线程调用。理解这些细节对掌握Java多线程编程至关重要。
39 13
|
9天前
|
安全 Java 开发者
【JAVA】封装多线程原理
Java 中的多线程封装旨在简化使用、提高安全性和增强可维护性。通过抽象和隐藏底层细节,提供简洁接口。常见封装方式包括基于 Runnable 和 Callable 接口的任务封装,以及线程池的封装。Runnable 适用于无返回值任务,Callable 支持有返回值任务。线程池(如 ExecutorService)则用于管理和复用线程,减少性能开销。示例代码展示了如何实现这些封装,使多线程编程更加高效和安全。
|
1月前
|
监控 Java
java异步判断线程池所有任务是否执行完
通过上述步骤,您可以在Java中实现异步判断线程池所有任务是否执行完毕。这种方法使用了 `CompletionService`来监控任务的完成情况,并通过一个独立线程异步检查所有任务的执行状态。这种设计不仅简洁高效,还能确保在大量任务处理时程序的稳定性和可维护性。希望本文能为您的开发工作提供实用的指导和帮助。
110 17
|
2月前
|
Java
Java—多线程实现生产消费者
本文介绍了多线程实现生产消费者模式的三个版本。Version1包含四个类:`Producer`(生产者)、`Consumer`(消费者)、`Resource`(公共资源)和`TestMain`(测试类)。通过`synchronized`和`wait/notify`机制控制线程同步,但存在多个生产者或消费者时可能出现多次生产和消费的问题。 Version2将`if`改为`while`,解决了多次生产和消费的问题,但仍可能因`notify()`随机唤醒线程而导致死锁。因此,引入了`notifyAll()`来唤醒所有等待线程,但这会带来性能问题。
Java—多线程实现生产消费者
|
1月前
|
缓存 安全 算法
Java 多线程 面试题
Java 多线程 相关基础面试题
AI助理

你好,我是AI助理

可以解答问题、推荐解决方案等