本文参考

本篇文章参考自《Effective Java》第三版第五条"Prefer dependency injection to hardwiring resources"

Static utility classes and singletons are inappropriate for classes whose behavior is parameterized by an underlying resource

静态工具类模式和单例模式都不适合应用到需要将底层资源作为自身字段进行参数化的类,这个引用的资源可以是一个接口,他对应有很多的实现,不同的实现应对不同的场景

静态工具类模式往往不需要进行实例化,而且有一个无参的private构造方法来强化noninstantiability的特性,他需要引用的资源在类加载时就已经被构建,尽管我们可以再设计一个静态方法来修改引用的资源,但并不是灵活和方便测试的方式

虽然单例模式存在一个实例,但是这个实例仅允许被初始化一次,所以引用的资源也只能被参数化一次,难以按照不同场景下的需求进行改变

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.

pass the resource into the constructor when creating a new instance

要解决上述问题,便要求能够用不同的资源构建不同的实例,我们可以通过构造方法来实现不同资源的参数化,这就是依赖注入的其中一种解决方案(同样可以应用到前述的静态工厂方法和构建者模式),这与Spring中的"构造注入"类似,它也能够保证不同的客户端共享同一份引用的资源,即"preserves immutability"

pass the resources, or factories to create them( refer to the fields using underlying resources ), 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.

a variant of the pattern is to pass a resource factory to the constructor

原文提供了一种使用Supplier<T>接口的Factory Method Pattern(工厂方法模式)

有关Supplier的使用,参考这篇文章:https://mkyong.com/java8/java-8-supplier-examples/

以马赛克为例,工厂方法模式的示例代码如下,顺便复习一下builder构建者模式

public class Tile {

  private String name;

  private int price;

  private String origin;

  public static class Builder {

    private String name;

    private int price;

    private String origin;

    public Builder name(String name) {

      this.name = name;

      return this;
    }

    public Builder price(int price) {

      this.price = price;

      return this;
    }

    public Builder origin(String origin) {

      this.origin = origin;

      return this;
    }

    public Tile build() {

      return new Tile(this);
    }
  }

  private Tile(Builder builder) {

    name = builder.name;

    price = builder.price;

    origin = builder.origin;
  }

  public String getName() { return name; }

  public int getPrice() { return price; }

  public String getOrigin() { return origin; }
}

public class Mosaic {

  private Tile tile;

  private String style;

  private Mosaic(String style) {

    this.style = style;
  }

  public static Mosaic create(Supplier<? extends Tile> tileFactory) {

    Tile tile = tileFactory.get();

    if (tile.getOrigin().equals("American")) {

      return new Mosaic("USA-STYLE");
    } else {

      return new Mosaic("GENERAL_STYLE");
    }
  }

  public Tile getTile() { return tile; }

  public String getStyle() { return style; }
}

public class SupplierExample {

  public static void main(String[] args) {

    Mosaic product = Mosaic.create(() -> new Tile.Builder().origin("American").build());

    System.out.println(product.getStyle());
  }
}

Effective Java —— 优先考虑依赖注入来引用资源的更多相关文章

  1. 在ABAP里模拟实现Java Spring的依赖注入

    Dependency Injection- 依赖注入,在Java Spring框架中有着广泛地应用.通过依赖注入,我们不必在应用代码里繁琐地初始化依赖的资源,非常方便. 那么ABAP能否从语言层面上也 ...

  2. Java Spring各种依赖注入注解的区别

    Spring对于Bean的依赖注入,支持多种注解方式: @Resource javax.annotation JSR250 (Common Annotations for Java) @Inject ...

  3. JavaEE(10) - Session EJB的依赖注入、引用及任务调度

    1. EJB依赖注入 #1. EJB开发(Net Beans创建EJB Module, 项目名称:CallHello) Hello.java package org.crazyit.service; ...

  4. JAVA框架 Spring 依赖注入

    一:介绍 情景:我们在给程序分层的时候:web层.业务层.持久层,各个层之间会有依赖.比如说:业务层和持久层,业务层的代码在调用持久层的时候,传统方式:new 持久层类. 进而进行调用,这种方式会导致 ...

  5. 详解Java Spring各种依赖注入注解的区别

    注解注入顾名思义就是通过注解来实现注入,Spring和注入相关的常见注解有Autowired.Resource.Qualifier.Service.Controller.Repository.Comp ...

  6. 【Java】 Spring依赖注入小试牛刀:编写第一个Spring ApplicationContext Demo

    0  Spring的依赖注入大致是这样工作的: 将对象如何构造(ID是什么?是什么类型?给属性设置什么值?给构造函数传入什么值?)写入外部XML文件里.在调用者需要调用某个类时,不自行构造该类的对象, ...

  7. Effective Java 第三版——43.方法引用优于lambda表达式

    Tips <Effective Java, Third Edition>一书英文版已经出版,这本书的第二版想必很多人都读过,号称Java四大名著之一,不过第二版2009年出版,到现在已经将 ...

  8. Java代码实现依赖注入

    http://zhangjunhd.blog.51cto.com/113473/126545 这里将模仿Spring实现一种基于xml配置文件的依赖注入机制.文件中将实现3中注入,一是单值注入,包括i ...

  9. Java反射及依赖注入简单模拟

    一.编写Dao类 ? 1 2 3 4 5 6 7 8 9 10 11 package cn.com.songjy.annotation;   import java.util.Date;   publ ...

随机推荐

  1. 60天shell脚本计划-3/12-渐入佳境

    --作者:飞翔的小胖猪 --创建时间:2021年2月6日 --修改时间:2021年2月10日 说明 每日上传更新一个shell脚本,周期为60天.如有需求的读者可根据自己实际情况选用合适的脚本,也可在 ...

  2. 移动C盘的.gradle文件

    今天参照一位博主的方法,移动了C盘下的.gradle文件,解放C盘,就是设置了一下环境变量,然后就把gradle文件移过去了,运行是可以运行,但是再看其他博主的方法都需要AndroidStudio下的 ...

  3. vue--axios异步请求及文件目录结构分析(个人记录)

    我这里使用axios进行异步加载 axios是一个库,并不是vue中的第三方插件,使用时不能通过Vue.use()安装插件,需要在原型上进行绑定,即直接在main.js中使用Vue.prototype ...

  4. JZ-017-树的子结构

    树的子结构 题目描述 输入两棵二叉树A,B,判断B是不是A的子结构.(ps:我们约定空树不是任意一个树的子结构) 题目链接: 树的子结构 代码 /** * 标题:树的子结构 * 题目描述 * 输入两棵 ...

  5. JZ-004-重建二叉树

    重建二叉树 题目描述 输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树.假设输入的前序遍历和中序遍历的结果中都不含重复的数字.例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序 ...

  6. Go redis hash存储结构体

    需求 需要存储用户数据到redis,结构是hash. 然后取出来,自动转成结构体. 结构体 type UserCache struct { Id int64 `json:"id"` ...

  7. JavaScript 数组方法filter和reduce

    前言 在ES6新增的数组方法中,包含了多个遍历方法,其中包含了用于筛选的filter和reduce filter 主要用于筛选数组的filter方法,在使用中,不会改变原数组,同时会将符合筛选条件的元 ...

  8. 二进制部署1.23.4版本k8s集群-6-部署Node节点服务

    本例中Master节点和Node节点部署在同一台主机上. 1 部署kubelet 1.1 集群规划 主机名 角色 IP CFZX55-21.host.com kubelet 10.211.55.21 ...

  9. 使用Logseq构建GTD系统

    2021-05-08: 1.0版本初步完成,待完善已完成任务回顾 2021-05-10: 1.1版本完成,修改不重要不紧急为将来清单,且新增每周回顾 前言 最近在阅读<小强升职记>,感觉里 ...

  10. 软件工程homework-001

          一. 回顾你过去将近3年的学习经历 1.当初你报考的时候,是真正喜欢计算机这个专业吗? 答:不喜欢,高中时候就已经对计算机比较抵触了,家里小时候比较富裕,九几年就在日本买了第一批家用台式机 ...