Java 從基礎到精通 — 第 10 講
使用層和測試創建可維護的應用程式
該部落格上撰寫的文章是出於教學目的而創建的。 另外,文章中的資訊可能不正確,請謹慎。
隨著程式的發展,變化傳播的程度變得比類別的數量更重要。 讓我們透過劃分規則、儲存和螢幕邊界並使行為可測試來結束我們的 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 結構並不是有很多層次結構的。 它是一種結構,其中改變狀態、外部資源和並發任務的生命週期的規則是明確的,並且可以在小單元中進行驗證。