本文参考

本篇文章参考自《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. C语言memcpy()函数和memmove()函数

    C语言memcpy()函数和memmove()函数 关于 memcpy() 函数,请先看链接. memcpy() 函数和 memmove() 函数的函数原型如下: void* memcpy(void ...

  2. JZ-030-连续子数组的最大和

    连续子数组的最大和 题目描述 HZ偶尔会拿些专业问题来忽悠那些非计算机专业的同学.今天测试组开完会后,他又发话了:在古老的一维模式识别中,常常需要计算连续子向量的最大和, 当向量全为正数的时候,问题很 ...

  3. 第五篇- 抖音的强大对手来了,用Flutter手撸一个抖音国际版,看看有多炫

    前言 由于中间几个月项目天天加班,导致没没时间更新,最近一段时间对前端进行了重构,加了很多页面,如登录.注册.关注.个人中心等,目前写这个纯属业余个人爱好,所以断断续续的继续在做...... 前端地址 ...

  4. xor加密的python实现

    #md5加密 import hashlib hash_md5 = hashlib.md5() x=input("Please input your text:") print( & ...

  5. Js-左侧折叠

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  6. 盘点十大GIS相关算法

    1.道格拉斯-普克算法(Douglas–Peucker) 道格拉斯-普克算法(Douglas–Peucker algorithm,亦称为拉默-道格拉斯-普克算法.迭代适应点算法.分裂与合并算法)是将曲 ...

  7. Redis(一):基本数据类型与底层存储结构

    最近在整理有关redis的相关知识,对于redis的基本数据类型以及其底层的存储结构简要的进行汇总和备注(主要为面试用) Redis对外提供的基本数据类型主要为五类,分别是 STRING:可以存储字符 ...

  8. jmeter关于入参转码encode问题

    我们的工作中,通过抓包经常会发现有很多入参都是被encode过一层,形成了如上图所示的样子: 这些参数我们是可以通过fiddler去转码的:但是如果我们要做jmeter的脚本,不可能每一次都手动去转码 ...

  9. interrupt(),interrupted() 和 isInterrupted() 的区别

    1. 结论先行 interrupt():将调用该方法的对象所表示的线程标记一个停止标记,并不是真的停止该线程. interrupted():获取当前线程的中断状态,并且会清除线程的状态标记.是一个是静 ...

  10. 1357:车厢调度(train) ybt

    1357:车厢调度(train) [题目描述] 有一个火车站,铁路如图所示,每辆火车从A驶入,再从B方向驶出,同时它的车厢可以重新组合.假设从A方向驶来的火车有nn节(n≤1000n≤1000),分别 ...