Effective Java笔记:优先考虑依赖注入来引用资源

Effective JAVA 笔记 快速回想一下effective java 阅读详情

书中提到了这种写法,Mosaic create(Supplier<? extends Tile> tileFactory)


1. 方法声明的含义解析

关键部分:

  1. Mosaic:

    • 此方法的返回类型是一个 Mosaic 对象。
  2. create:

    • 这是方法名称,表明这个方法的作用是 “创建” 一个 Mosaic 对象。
  3. Supplier<? extends Tile> tileFactory:

    • 参数类型是 Supplier,它是一个函数式接口,允许 惰性提供(lazy supply) 一个 Tile 的实现。
    • ? extends Tile 是 泛型通配符,表示调用者可以传递一个 Supplier,该 Supplier 返回类型可以是 Tile 或其子类。

翻译成自然语言:
这个方法是一个静态工厂方法,用于创建一个 Mosaic 对象。调用方需要向方法提供一个 Supplier,该 Supplier 能够生成一个 Tile 的实例(可能是某个具体子类的实例,而非Tile本身)。


2. 为什么使用 Supplier<? extends Tile>

问题背景:

在传统的工厂设计模式中,创建一个 Mosaic 通常会直接传入一个具体的 Tile 对象,例如:

Mosaic mosaic = new Mosaic(new ConcreteTile());

然而,这种方式存在以下问题:

  1. 强耦合性:
    调用方需要直接提供 ConcreteTile 的实例。如果想动态决定实例化逻辑(如:参数配置、动态初始化),则需要大量冗余代码。

  2. 缺乏灵活性:
    如果需要按需生成不同的 Tile 子类,或者需要延迟构造(Lazy Initialization),传统构造方法难以高效实现。

Supplier 提供的优势:

Java 8 引入 java.util.function.Supplier 这一函数式接口,能够为我们提供更灵活的创建方式:

  1. 延迟生成(Lazy Evaluation):

    • Supplier 是一个无参方法的函数式接口,只在真正需要 Tile 对象时才会调用。例如,只有在 Mosaic 确保需要一个 Tile 后,它才会调用 tileFactory.get() 生成实例,避免浪费资源。
  2. 灵活支持多态(子类):

    • 使用 ? extends Tile 表示,tileFactory 可以生产 Tile 或其子类。调用者无需关心 Mosaic 的具体实现,只需要提交合适的工厂方法即可。
  3. 高扩展性:

    • 不同的 Supplier 可以实现不同的对象创建方式(如具体子类的选择、对象池的复用、动态参数配置等)。

3. 实际使用中的优势

  • 简单且灵活的对象生成:
    你不需要绑定具体的 Tile 实例,可以根据需求动态提供 Supplier。

  • 接口表达意图:
    通过使用 Supplier,明确了 Mosaic 的实现只需要知道如何生成 Tile,它无需了解 Tile 的具体实现细节。这符合 “依赖倒置原则”。

  • 更好的兼容 Java 的流式 API 和函数式编程:
    Supplier 是标准函数式接口,极其方便配合 Stream、Optional 等 Java 8+ 的特性使用。


4. 示例:Mosaic 和 Tile 的实际应用场景

假设你正在开发一个拼图游戏,每个拼图由若干 Tile(小方块)组成,而 Mosaic 是由这些方块拼接起来的大图片。
Tile 有多个具体实现(例如 ColorTile, ImageTile)。

基类和子类定义:

// Tile 是拼图的基础
public interface Tile {
    void draw(); // 每个 Tile 都可以被绘制
}

// ColorTile 是 Tile 的具体实现,绘制一块特定的颜色
public class ColorTile implements Tile {
    private final String color;

    // 构造器
    public ColorTile(String color) {
        this.color = color;
    }

    @Override
    public void draw() {
        System.out.println("Drawing a tile with color: " + color);
    }
}

// ImageTile 是另一种 Tile,它绘制图片
public class ImageTile implements Tile {
    private final String imagePath;

    public ImageTile(String imagePath) {
        this.imagePath = imagePath;
    }

    @Override
    public void draw() {
        System.out.println("Drawing a tile with image: " + imagePath);
    }
}

Mosaic 定义:

import java.util.List;
import java.util.ArrayList;
import java.util.function.Supplier;

public class Mosaic {
    private final List<Tile> tiles = new ArrayList<>();

    // 私有化构造器,强制使用静态方法构造
    private Mosaic(List<Tile> tiles) {
        this.tiles.addAll(tiles);
    }

    // 静态工厂方法
    public static Mosaic create(Supplier<? extends Tile> tileFactory) {
        List<Tile> tiles = new ArrayList<>();
        
        // 示例:创建 5 个 Tile,通过 tileFactory 提供不同的类型
        for (int i = 0; i < 5; i++) {
            tiles.add(tileFactory.get());
        }

        return new Mosaic(tiles);
    }

    // 为 Mosaic 上的所有 Tile 绘制图像
    public void draw() {
        tiles.forEach(Tile::draw);
    }
}

使用 Mosaic.create 建立不同的 Mosaic 拼图:

1. 提供 ColorTile 工厂
Mosaic colorMosaic = Mosaic.create(() -> new ColorTile("Red"));
colorMosaic.draw();
/*
输出:
Drawing a tile with color: Red
Drawing a tile with color: Red
Drawing a tile with color: Red
Drawing a tile with color: Red
Drawing a tile with color: Red
*/
2. 提供 ImageTile 工厂
Mosaic imageMosaic = Mosaic.create(() -> new ImageTile("image.jpg"));
imageMosaic.draw();
/*
输出:
Drawing a tile with image: image.jpg
Drawing a tile with image: image.jpg
Drawing a tile with image: image.jpg
Drawing a tile with image: image.jpg
Drawing a tile with image: image.jpg
*/
3. 动态选择 Tile 类型

你可以通过业务逻辑动态决定生成哪种 Tile:

Mosaic mixedMosaic = Mosaic.create(() -> {
    if (Math.random() > 0.5) {
        return new ColorTile("Blue");
    } else {
        return new ImageTile("pattern.jpg");
    }
});
mixedMosaic.draw();
/*
输出(随机):
Drawing a tile with color: Blue
Drawing a tile with color: Blue
Drawing a tile with image: pattern.jpg
Drawing a tile with color: Blue
Drawing a tile with image: pattern.jpg
*/

总结

Mosaic create(Supplier<? extends Tile> tileFactory) 采用了现代 Java 编程的最佳实践:

  1. 函数式接口的优雅性:通过 Supplier 提供控制反转,让调用者决定如何生成 Tile 实例。
  2. 灵活多态机制:利用 ? extends Tile,Mosaic 可以兼容 Tile 的任意子类,不必限制为 Tile 本身。
  3. 惰性(Lazy)评估:只有在实际需要时才会创建 Tile 对象(tileFactory.get())。
《iOS之一起进大厂》系列-秒杀面试官的RunLoop底层原理面试题 Runloop是iOS面试中的必考题,不管大厂小厂都会问到。 这里包括了Runloop几乎所有的面试题,还有中肯完整的答案解释。 阅读详情

相关推荐

【ComfyUI】【Nunchaku】【diffusers报错解决】秋叶整合包安装 Nunchaku 报错的解决方法

最近在折腾 AI 绘图时,我尝试在秋叶的 ComfyUI 整合包中安装 `ComfyUI-nunchaku` 插件(版本 0.3.3),结果启动后直接报错,提示无法从 `accelerate.utils.memory` 中导入 `clear_device_cache`,让我一度怀疑插件是否兼容。查阅了一堆 issue 和源码之后,总算找到了原因和解决方法。

代码简单说 Vue、JAVA、PHP、Node.js 熟练运用,接口、架构、性能全搞定。 1856

Effective Java笔记(5)优先考虑依赖注入来引用资源

这是依赖注入( dependency injection )的一种形式:词典(dictionary )是拼写检查器的一个依赖( depend ency ),在创建拼写检查器时就将词典注入( injected )其中。建议尝试用 SpellChecker 来支持多词典,即在现有的拼写检查器中,设 dictionary域为 nonfinal ,并添加一个方法用它来修改词典,但是这样的设置会显得很笨拙、容易出错,并且无法并行工作。实际上,每一种语言都有自己的词典,特殊同汇还要使用特殊的词典。

琅琊之榜 605

Transformer实战——Transformer自编码模型

自编码模型依赖于原始 Transformer 编码器,并且在解决分类问题时非常高效。除了 BERT 外,还有许多流行的自编码模型,在本节中,我们将一些除 BERT 外的自编码模型,这些模型的目标是通过优化预训练过程、增加层数或头数、改善数据质量、设计更好的目标函数等,来在下游任务上取得更好的表现。这些改进大致可以分为两个方面,更好的架构设计选择和预训练控制。

盼小辉丶的博客 9326

Effective Java学习笔记--优先考虑依赖注入来引用资源

Java的类往往不是独立的,而是依赖一个或者多个底层的资源来构建的。就比如一个蛋糕,必须要依靠一个模子才能做出想要的形状。这里,作者举了一个拼写检查器的例子,一个拼写检查器必须要依赖一本或多本词典才能去做校验。

weixin_50353846的博客 477

40、基于指令的GPU编程:OpenACC与OpenMP的深入解析

本文深入解析了两种基于指令的GPU编程模型——OpenACC和OpenMP。从编程复杂度、数据处理方式和性能表现等多个方面对两者进行了对比分析,并结合实际应用场景提供了选择建议。通过详细的代码示例和性能测试结果,帮助开发者更好地理解和应用这两种编程模型,以充分发挥GPU的并行计算能力。

q5r6s7的博客 134

uniapp - 超详细 H5 网页引入百度地图教程,附地图示例 / 获取当前设备定位的省市区、详细地址、经纬度信息 / 用户当前 IP 属地定位地理位置等等(新手小白快速上手,详细配置及使用全流程)

uniapp百度地图,uniapp百度地图ip属地定位,uniapp百度地图获取省市区详细地址经纬度等,uniapp百度地图当前用户设备定位省份市区详细所在地ip属地等详细教程示例,uniapp网页h5引入百度地图详细教程,uniapp h5网站使用百度地图详细教程,uniappH5端如何接入使用百度地图api,uniapp H5网页端百度地图获取地理位置信息,uniapp h5页面引入百度地图,uniapp h5平台百度地图获取城市信息,uniapp百度地图获取经纬度,uniapp 百度地图拿省市区用什么

🏆 前端领域优质创作者 6217

《Effective Java》学习笔记 - (5) 优先考虑依赖注入来引用资源

依赖注入在这里的含义就是把一个类当作参数传入到另一个类中。在这一节提到,如果是想要在一个类中使用另一个类的资源,那么最好就是使用依赖注入。

Jwasx的博客 406

【SigmaStudio】自定义算法组件之XML编写规范(一)

SigmaStudio生成自定义算法组件时,需要XML和DLB文件,本文主要记录XML文件的编码规范

liang_song的博客 1140

解读 Java 经典巨著《Effective Java》90条编程法则,第5条:优先考虑依赖注入来引用资源

Joshua Bloch 在《Effective Java》中提出的第5条编程法则“优先考虑依赖注入来引用资源”着重强调了依赖注入(DI)的重要性,该法则主要关注如何有效地管理类和资源之间的依赖关系。

赵士杰——成功并非一蹴而就,而是在持之以恒的努力中逐渐实现。 1631

javafx结合Scene Builder自定义fxml实现漂亮的登录界面、自定义最小化、关闭按钮

本节主要介绍了如何结合Scene Builder工具来制作一个好看又漂亮的登录界面,以及介绍了如何在程序中调用生成界面文件fxml文件,如何获取到fxml文件中的组件等,并演示登录、最小化和关闭等功能。

c1007857613的专栏 5222

AMBA-CHI协议详解(七)

本节描述该协议包含的支持系统保序需求的机制。

Crazzy_M的博客 1158

《Effective Java》第五条:优先考虑依赖注入来引用资源

《Effective Java》第五条的核心思想是:类不应自行创建其依赖的资源(如数据库连接、网络服务、配置信息等),而应通过外部传入(即 “依赖注入”)的方式获取,以提高灵活性、可测试性和复用性。 很多类在实现时会 “硬编码” 依赖资源,例如在类内部直接创建数据库连接、实例化特定服务等。这种做法存在三个严重问题:硬编码的本质是 **“类自己创建依赖”,而测试需要的是“替换依赖为测试替身(如 Mock 对象)”**,这两者是矛盾的。假设我们有一个发送短信的服务类,硬编码了具体的短信网关实现: 如果我们

papilon_的博客 789

线结构光相机原理详解以及精度控制总结

摘要:线阵结构光相机是工业三维检测的核心设备,结合线阵相机的高分辨率与结构光的主动三维成像能力。其工作原理基于线激光投射、逐线扫描、亚像素级条纹提取及三角测量法实现三维重建。精度受硬件、校准、环境和算法四因素影响,需通过优化硬件选型(如小像元相机、窄线宽激光)、精准校准(相机内参、激光平面)、环境控制(遮光、隔振、恒温)及算法优化(Steger算法、点云后处理)来提升。典型应用(卷材、轨道检测)中深度精度可达5-20μm,需根据场景需求平衡参数配置。

start_up_go的博客 940

《Effective Java》第5条:优先考虑依赖注入来引用资源

带有 Supplier的方法,通常应该限制输入工厂的类型参数使用有限制的通配符类型(即不要使用Object这种类型,这种没有限制),详见第31条,以便客户端能够传入一个工厂,来创建指定类型的任意子类型。原文P17:满足该需求的最简单的模式是:当创建一个新的实例时,就将该资源传到构造器中。这是依赖注入(dependencyinjection)的一种形式:词典(dictionary)是拼写检查器的一个依赖(dependency),在创建拼写检查器时就将词典注入(injected)其中。(Spring用的最多)

TD_FAlmK的博客 847

文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况

主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。

ET2012新版免狗免安装绿色软件

ET2012新版免狗免安祖昂绿色软件。,新界面,新视觉,

《Effective Java》解读第5条:优先考虑依赖注入来引用资源

摘要:本文探讨了依赖注入(DI)在Java开发中的重要性。通过对比静态工具类和单例模式,指出它们依赖硬编码、缺乏灵活性的缺陷。推荐使用依赖注入模式,通过构造函数或setter方法从外部注入依赖,从而提高代码的灵活性、可测试性和松耦合性。文章详细介绍了Spring Boot中三种依赖注入方式(构造器注入、setter注入和字段注入)及其优缺点,建议在大型项目中使用DI框架(如Spring)管理复杂依赖关系。依赖注入是现代Java开发中实现高质量代码的关键实践。

Cosmoshhhyyy的博客 628

SAP B1中文培訓教材_SDK

公司内部培训资料,对开发工具 ,DIAPI, UIAPI,Add-ON有详细解说

Effective Java -- 引用资源时优先依赖注入

此系列文章为本人对《Effective Java》一书的学习笔记,主要是记录对书中重点内容的理解。既然有缘看到此文,那么希望能对你有所帮助。本文对应原书 第5条 优先考虑依赖注入来引入资源

心之所往 码之所向 321

Devexpress16.2.6破解工具

Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具

Effective Java3.5-优先考虑依赖注入来引用资源

5 优先考虑依赖注入来引用资源 主要内容:讲述在使用静态工具类,Singleton类时,最好不要依赖于其他的底层资源类,意味着静态工具类和Singleton最好是独立的类,即使需要用到其他的参数,也最好不要引用其他对象,更不要是一个类的同种变形(比如它的子类们或者组合类) 主要目标:使用静态工具类,Singleton类时不引用特定的(底层)资源。创建实例时就将资源(另一个对象)传到构造器。使用Supplier来控制资源(另一个对象)的类型(上界)。使用资源工厂来获得资源,并将工厂作为“另一个对象”作为传到

JunxuanBo 329

笔记《Effective Java》01: 创建和销毁对象

《Effective Java》这本书可以说是程序员必读的书籍之一。这本书讲述了一些优雅的,高效的编程技巧。对一些方法或API的调用有独到的见解,还是值得一看的。刚好最近重拾这本书,看的是第三版,顺手整理了一下笔记,用于自己归纳总结使用。建议多读一下原文。今天整理第一章节:创建和销毁对象。

有一只柴犬的专栏 1852

Effective Java -- 创建和销毁对象 -- 优先考虑依赖注入来引用资源

第二章 创建和销毁对象 第五条 优先考虑依赖注入来引用资源 不要用静态工具类或Singleton来实现依赖。 应该使用依赖注入,将这些资源或工厂传给构造方法,提高类的灵活性、可重用性和可测试性。

weixin_43164759的博客 401

05.依赖注入优先于硬连接资源

前言 《Effective Java》中文第三版,是一本关于Java基础的书,这本书不止一次有人推荐我看。其中包括我很喜欢的博客园博主五月的仓颉,他曾在自己的博文《给Java程序猿们推荐一些值得一看的好书》中也推荐过。加深自己的记忆,同时向优秀的人看齐,决定在看完每一章之后,都写一篇随笔。如果有写的不对的地方、表述的不清楚的地方、或者其他建议,希望您能够留言指正,谢谢。 《Effective Ja...

龚国玮的博客 1166

小鸡爪读Effective Java记录4:优先考虑依赖注入来引用资源

小鸡爪学习Effective java,简简单单例子理解依赖注入,小鸡爪觉得这更多的是思维方式的转化,对我们帮助很大。

weixin_44339617的博客 455

Effective Java读书笔记

第一章 引言 本文用来记录Effective Java学习过程中的各个知识点,受此时能力所限,有些点可能讲的不太清楚,或者理解有错误的地方,请多多指教! 第二章 创建和销毁对象 第一条 用静态工厂方法代替构造器 可参考文章:https://blog.youkuaiyun.com/u014129886/article/details/89670049 总而言之,静态工厂方法和共有构造器各有各的用处,我们需要理解他们各自的长处,静态工厂经常更加合适。 此处的静态工厂方法与设计模式中的工厂模式不同,这里是一种构造

逆水行舟,不进则退 1441

深入理解《Effective Java》 之 条目5:优先考虑通过依赖注入来连接资源

指的是一个类做的事情(行为),不是固定的,而是。

墨问的专栏 359

优先考虑依赖注人来引用资源

优先考虑依赖注人来引用资源 有许多类需要依赖底层资源,比如我们有个类需要依赖底层的字典资源,像下面这样做成静态域的,或者把类做成Singleton的都是很常见的。 public class Word { private static final Dictionary DICTIONARY = new Dictionary(); } 但是这只是作为有一本字典的情况下,当我们在不同的情况下需...

weixin_44130081的博客 1248

Effective Java(3版)第二章 第五条 优先考虑依赖注入来引用资源详解

文章摘要: 本文详细介绍了依赖注入设计模式及其实现方式。依赖注入的核心思想是将依赖对象的创建与使用分离,通过控制反转由外部提供依赖对象。文章对比了传统非DI方式与依赖注入的区别,并阐述了三种依赖注入实现方式:基本依赖注入、工厂方法注入(使用Java8的Supplier接口)以及Spring框架注入。特别分析了工厂方法注入的优势,包括延迟创建、复杂创建逻辑处理等。最后总结了依赖注入的最佳实践,强调避免内部创建依赖、合理选择注入方式等原则。全文通过代码示例展示了各种注入方式的具体实现,为设计松耦合、可测试的系统

qq_47129343的博客 387

《Effective Java》读书笔记一

优先考虑依赖注入来引用资源可以使代码更加灵活、可测试和易于维护,是一种有效的设计实践。

qq_41831136的博客 772
上一篇: Effective Java笔记:用私有构造器或者枚举类型强化 Singleton 属性
下一篇: Effective Java笔记 :覆盖 equals 时请遵守通用约定
Jooou
博客等级 码龄9年 226粉丝 58原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值