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 是标准函数式接口,极其方便配合 StreamOptional 等 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())。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值