Effective第三版 中英 | 第二章 创建和销毁对象 | 固定资源首选使用依赖注入

news/2024/12/2 20:48:56/

文章目录

  • Effective第三版
    • 前言
    • 第二章 创建和销毁对象
      • 固定资源首选使用依赖注入

Effective第三版

前言

大家好,这里是 Rocky 编程日记 ,喜欢后端架构及中间件源码,目前正在阅读 effective-java 书籍。同时也把自己学习该书时的笔记,代码分享出来,供大家学习交流,如若笔记中有不对的地方,那一定是当时我的理解还不够,希望你能及时提出。如果对于该笔记存在很多疑惑,欢迎和我交流讨论,最后也感谢您的阅读,点赞,关注,收藏~

前人述备矣,我只是知识的搬运工,effective 书籍源码均在开源项目 java-diary 中的 code-effective-third 模块中

源代码仓库地址: https://gitee.com/Rocky-BCRJ/java-diary.git

第二章 创建和销毁对象

固定资源首选使用依赖注入

在这里插入图片描述

  Many classes depend on one or more underlying resources. For example, a spell checker depends on a dictionary. It is not uncommon to see such classes implemented as static utility classes(Item 4):

  许多类依赖于一个或多个底层资源。例如,拼写检查器依赖于字典。常见的做法是将这些类实现为静态实用程序类(第 4 项):

// Inappropriate use of static utility - inflexible & untestable!
public class SpellChecker {private static final Lexicon dictionary = ...;private SpellChecker() {} // Noninstantiablepublic static boolean isValid(String word) { ... }public static List<String> suggestions(String typo) { ... }
}

  Similarly, it’s not uncommon to see them implemented as singletons (Item 3):

  同样的,将它们作为单例实现的情况并不少见(第 3 项):

// Inappropriate use of singleton - inflexible & untestable!
public class SpellChecker {private final Lexicon dictionary = ...;private SpellChecker(...) {}public static INSTANCE = new SpellChecker(...);public boolean isValid(String word) { ... }public List<String> suggestions(String typo) { ... }
}

  Neither of these approaches is satisfactory, because they assume that there is only one dictionary worth using. In practice, each language has its own dictionary, and special dictionaries are used for special vocabularies. Also, it may be desirable to use a special dictionary for testing. It is wishful thinking to assume that a single dictionary will suffice for all time.

  这些方法都不令人满意,因为它们假设只有一本值得使用的字典。在实践中,每种语言都有自己的字典,特殊字典用于特殊词汇。而且,可能需要使用特殊字典进行测试。假设单本字典就足以满足所有情况,这是一厢情愿的想法。

  You could try to have SpellChecker support multiple dictionaries by making the dictionary field nonfinal and adding a method to change the dictionary in an existing spell checker, but this would be awkward, error-prone, and unworkable in a concurrent setting. Static utility classes and singletons are inappropriate for classes whose behavior is parameterized by an underlying resource.

  你可以尝试让 SpellChecker 支持多个词典,方法是使字典字段为非 final 域,并添加一个方法来更改现有拼写检查器中的字典,但这在并发时设置会很笨拙,容易出错并且不可行。静态实用程序类和单例不适用于将底层资源作为参数的类(Static utility classes and singletons are inappropriate for classes whose behavior is parameterized by an underlying resource.)。

  What is required is the ability to support multiple instances of the class (in our example, SpellChecker), each of which uses the resource desired by the client (in our example, the dictionary). A simple pattern that satisfies this requirement is to pass the resource into the constructor when creating a new instance. This is one form of dependency injection: the dictionary is a dependency of the spell checker and is injected into the spell checker when it is created.

  所需要的是能够支持类的多个实例(在我们的示例中为 SpellChecker),每个实例都使用客户端所需的资源(在我们的示例中为字典)。满足此要求的简单模式是在创建新实例时将资源传递给构造函数。这是依赖注入的一种形式:字典是拼写检查器的依赖项,并在创建时注入拼写检查器。

// Dependency injection provides flexibility and testability
public class SpellChecker {private final Lexicon dictionary;public SpellChecker(Lexicon dictionary) {this.dictionary = Objects.requireNonNull(dictionary);}public boolean isValid(String word) { ... }public List<String> suggestions(String typo) { ... }
}

  The dependency injection pattern is so simple that many programmers use it for years without knowing it has a name. While our spell checker example had only a single resource (the dictionary), dependency injection works with an arbitrary number of resources and arbitrary dependency graphs. It preserves immutability (Item 17), so multiple clients can share dependent objects (assuming the clients desire the same underlying resources). Dependency injection is equally applicable to constructors, static factories (Item 1), and builders (Item 2).

  这种依赖注入很简单,以至于程序猿用了很多年却不知道它有一个名称。虽然我们的拼写检查器只有一个资源(字典),但是依赖注入可以使用任意数量的资源和任意的依赖关系,它保留了不变性(第 17 项),因此多个客户端可以共享依赖对象(假设客户端需要相同的底层资源)。依赖注入同样适用于构造函数、静态工厂(第 1 项)和构建器(第 2 项)。

  A useful variant of the pattern is to pass a resource factory _to the constructor. A factory is an object that can be called repeatedly to create instances of a type. Such factories embody the _Factory Method pattern [Gamma95]. The Supplier interface, introduced in Java 8, is perfect for representing factories. Methods that take a Supplier on input should typically constrain the factory’s type parameter using a bounded wildcard type (Item 31) to allow the client to pass in a factory that creates any subtype of a specified type. For example, here is a method that makes a mosaic using a client-provided factory to produce each tile:

  将资源工厂传递给构造函数就会变成一个有用的模式。工厂是一个对象,通过重复调用这个工厂可以创建某个类型的实例对象。这些就是工厂方法模式 [Gamma95]。Java 8 中引入的 Supplier<T>;接口非常适合体现工厂。在输入上采用 Supplier<T>的方法通常应该使用泛型(第 31 项)约束工厂的类型参数,以允许客户端传入创建指定类型的任何子类型的工厂。例如,这是一种使用客户提供的工厂生成马赛克来生成每个图块的方法:

Mosaic create(Supplier<? extends Tile> tileFactory) { ... }

  Although dependency injection greatly improves flexibility and testability, it can clutter up large projects, which typically contain thousands of dependencies. This clutter can be all but eliminated by using a dependency injection framework, such as Dagger [Dagger], Guice [Guice], or Spring [Spring]. The use of these frameworks is beyond the scope of this book, but note that APIs designed for manual dependency injection are trivially adapted for use by these frameworks.

  尽管依赖注入极大地提高了灵活性和可测试性,但它可能会使大型项目更加混乱,这些项目通常包含数千个依赖项。通过使用依赖注入框架,例如 Dagger [Dagger],Guice [Guice]或 Spring [Spring],可以消除这种混乱。这些框架的使用超出了本书的范围,但请注意,为手动依赖注入而设计的 API 可以轻松地适用于这些框架。

  In summary, do not use a singleton or static utility class to implement a class that depends on one or more underlying resources whose behavior affects that of the class, and do not have the class create these resources directly. Instead, pass the resources, or factories to create them, into the constructor (or static factory or builder). This practice, known as dependency injection, will greatly enhance the flexibility, reusability, and testability of a class.

  总之,如果有一个类依赖一个或多个底层资源的类,并且底层资源类影响了类的行为,不要使用单例或静态实用程序类来实现它,并且不要让类直接创建这些资源(do not use a singleton or static utility class to implement a class that depends on one or more underlying resources whose behavior affects that of the class)。相反,将资源或工厂传递给构造函数(或静态工厂或构建器)。这种做法称为依赖注入,将极大地增强类的灵活性,可重用性和可测试性。


http://www.ppmy.cn/news/272662.html

相关文章

C#,码海拾贝(37)——求解“托伯利兹方程组“的“列文逊方法“之C#源代码

using System; namespace Zhou.CSharp.Algorithm { /// <summary> /// 求解线性方程组的类 LEquations /// 原作 周长发 /// 改编 深度混淆 /// </summary> public static partial class LEquations { /// <summary> /…

Servlet 详解

目录 什么是 servlet? Servlet 是做甚的? 如何编写一个 Servlet 程序? 解析访问出错情况 Servlet 的运行原理 1. 接收请求 2. 根据请求计算响应 3. 返回响应 Servlet API 详解 HTTPServlet HttpServletRequset HttpServletResponse 什么是 servlet? Servlet 是…

奇虎360 php t5级别,奇虎360凭什么估值3800亿?核心价值只是他而已!

最近360在国内上市的各种消息不断的流出&#xff0c;作为中国互联网领域重要的力量&#xff0c;360曾经在美国纳斯达克短暂上市。但是因为美国人民对360的业务部太认可&#xff0c;加上周鸿祎忽悠美国人不给力&#xff0c;导致360市值低的难以启齿。面临这个局面&#xff0c;36…

Glint360K | 使用指南

首先恭喜格林深瞳3月18日在科创板成功上市 一、介绍 Glint360K数据集包含36万类别的1800万张图像&#xff0c;不论是类别数还是图像数&#xff0c;相比MS1MV2数据集都有大幅提升。 这是一个号称全球最大最干净的人脸数据集&#xff0c; 下载地址&#xff08;我自己上传的&…

停车还能360全方位影像_2020款新途锐锐享版上市,智能泊车360全景影像加量不加价...

前一阵子和大家说过20款途锐即将上市并会有很多新的升级项目&#xff0c;而最近20款途锐3.0锐享版已经开始打响头炮&#xff0c;官方报价71.8W&#xff0c;比3.0锐锋版价位略高&#xff0c;比百万纪念版相差5W&#xff0c;高配锐智版相差10W左右。 今天我们就来看看这款新车途锐…

奇虎360回归A股要如何上市?多家上市公司否认360借壳

奇虎360私有化回归A股将选择借壳哪家上市公司&#xff1f;此事引发了诸多投资者的猜测&#xff0c;但是&#xff0c;不少上市公司都对此予以否认。中葡股份7月29日晚间公告&#xff0c;经向公司控股股东中信国安集团有限公司函证确认&#xff0c;截至目前&#xff0c;公司控股股…

周鸿祎雷军口水战 360特供机上市将考验小米

最近&#xff0c;周鸿祎与雷军微博口水战已经持续快一个月了&#xff0c;整个过程&#xff0c;对360呈现利好趋势&#xff0c;对于360来说&#xff0c;目前特供机还未上市&#xff0c;但一开始便把特供机放在与小米平起平坐的位置。同时&#xff0c;由于口水战的持久性&#xf…

转载:360上市:一个昂贵的免费故事

30日晚&#xff0c;北京豪华会所九朝会&#xff0c;IT记者们受360公司之邀参与晚会&#xff0c;等待身在大洋彼岸的周鸿祎的视频采访。这些记者当年都收到《免费》这本书&#xff0c;赠书者为周鸿祎。当时没有人相信周鸿祎“免费可赚钱、赚大钱”的故事&#xff0c;有记者还拒绝…