← SEARCHABLE ARCHIVE
Java · 2026-08-12

从 Java 基础到掌握 — 第 10 集

使用层和测试创建可维护的应用程序

INTERACTIVE READING MODE →

该博客上撰写的文章是出于教学目的而创建的。 另外,文章中的信息可能不正确,请谨慎。

随着程序的发展,变化传播的程度变得比类的数量更重要。 让我们通过划分规则、存储和屏幕边界并使行为可测试来结束我们的 Java 系列。

责任层次

public final class OrderService {
    private final ItemRepository repository;

    public OrderService(ItemRepository repository) {
        this.repository = repository;
    }

    public OrderResult buy(int itemId, int gold) {
        Item item = repository.find(itemId)
            .orElseThrow(() -> new ItemNotFoundException(itemId));

        if (gold < item.getPrice()) {
            return OrderResult.notEnoughGold();
        }

        return OrderResult.success(item, gold - item.getPrice());
    }
}

该服务负责购买规则,并不直接了解数据库或HTTP实现细节。 控制器或屏幕将输入传递给服务并呈现结果。

将依赖关系置于外部

public interface ItemRepository {
    Optional<Item> find(int id);
}

ItemRepository repository = new FileItemRepository(path);
OrderService service = new OrderService(repository);

如果在构造函数之外选择具体存储,测试可以用内存实现替换它。 接口并不是每个类的装饰,而是放置在外部技术变化的边界处。

试运行

@Test
void purchaseKeepsRemainingGold() {
    ItemRepository repository = new MemoryItemRepository(
        new Item(10, "Potion", 30)
    );
    OrderService service = new OrderService(repository);

    OrderResult result = service.buy(10, 100);

    assertEquals(70, result.getRemainingGold());
}

该测试检查外部可见的规则而不是内部方法调用顺序。 即使您清理了实现,您也可以查看相同的合同是否适用于相同的输入。

项目工具

Gradle 或 Maven 将编译、测试、库版本控制和打包成可重复的命令。 将构建文件和测试放在存储库中,以便项目不仅仅在开发环境中运行。

一个好的 Java 结构并不是有很多层次结构的。 它是一种结构,其中改变状态、外部资源和并发任务的生命周期的规则是明确的,并且可以在小单元中进行验证。