在 OOP 的情境下,通常一個 class 會需要其它資源的協助,假定 UserChecker 是驗證使用者身分的服務,它需要負責驗證機制的 class 來確認使用者身分。驗證機制為 AuthMechanism。然後將 UserChecker 當作像工具類別 (Utility class) 來處理。
public class UserChecker {
private static final AuthMechanism mechanism = new AuthMechanism();
private UserChecker() { }
public static boolean login(String username, String password) { ... }
}
當然也可以將 UserChecker 採用 singleton 作法。public class UserChecker {
private final AuthMechanism mechanism = ...;
private UserChecker(...) { }
public static final UserChecker INSTANCE = new UserChecker(...);
public boolean login(String username, String password) { ... }
}
以上兩種作法都不理想,因為它們都假設只會有一種 AuthMechanism 可用,當 AuthMechanism 有多種實作時,像是 hashed password 驗證方式,OAuth 驗證方式等。UserChecker 若要支援多種 AuthMechanism,上面兩種架構就較難擴充,而且在測試上,static 物件比較難作測試。Utility class 及 singleton class 不適合當作引用資源的方式。其實最簡單的方式就是將 AuthMechanism 傳入 UserChecker 的 constructor,而 UserChecker 不需要去負責生成它需要的資源,這就是 dependency injection。當作資源的 class 需為 immutable,讓更多不同的 class 可以共享它們,dependency injection 可以適用在 constructor、static factory 及 builder。
public class UserChecker {
private final AuthMechanism mechanism;
private UserChecker(AuthMechanism mechanism) {
this.mechanism = mechanism;
}
public boolean login(String username, String password) { ... }
}
雖然 dependency injection 的設計方式較靈活,較容易進行測試,但在大型專案下,有非常多的 dependency 需要設定,這樣往往會讓架構越來越凌亂,所以可以使用套件來管理 dependency injection 這件事,最常見的就是 Spring Framework。Spring Framework轉載請註明原文網址 https://cookieandcoketw.blogspot.com/2020/06/effective-java-5-dependency-injection.html
https://spring.io/projects/spring-framework
沒有留言:
張貼留言