TL; DR沒有一個靈丹妙藥解決了這個,但很多不同的工具來利用
有很多種不同的技術來隔離軟件應用程序的不同部分,但我不認爲有任何解決方案可以解決所有問題。一些構建系統可以限制目標之間的依賴關係(例如,Bazel在構建目標上具有visibility
屬性,可以阻止一個目標依賴於另一個目標,即使它們通過Java的類可見性彼此都可見),這些目標可以與Java內置可見性。例如:
// Foo.java
package com.yourcompany.foo;
public class Foo {}
// Build rule for Foo.java
java_library(
name = "Foo",
srcs = ["Foo.java"],
# Restricts visibility to this directory, even though
# the class visibility was "public"
visibility = ["//visibility:private"],
)
// Bar.java
package com.yourcompany.bar;
import com.yourcompany.foo.Bar; // prevented by build visibility system
public class Bar {
Foo foo = new Foo();
}
另外,也可以使用接口來介導的邏輯組件之間的所有交互,並隱藏這些接口的實現(例如,僅通過服務註冊表接口或通過接口依賴注入暴露實現)。例如,對於Dagger,可以創建用於每個層的單獨component,這將允許你寫類似的代碼:
final class ControllerImpl implements Controller {
// Since "ControllerImpl" is instantiated/wired into the
// controller layer, the database dependency is available/
// exposed for injection within this layer. The access control is
// strictly performed by the way the dependencies are wired.
@Inject
public ControllerImpl(Database database) {
// ...
}
}
除了上述,可以使用依賴關係分析/依賴性分析測試或commit鉤子自動檢測依賴性規則違規(並根據它們觸發錯誤/拒絕提交)。例如,一個窮人的解決方案就是簡單地掃描每個文件的包聲明及其導入語句,然後採用一些啓發式方法來檢測不良依賴。
另一種方法是將不同的組件捆綁到單獨的JAR中,並使用自定義的ClassLoader加載它們,這樣可以防止使用反射進行非法訪問(否則可能會繞過任何程序結構)。
除了自動化方法,手動方法也有其價值。手動方法包括在代碼審查和審計期間執行的常規代碼審查和策略。
總之,沒有一個正確的答案。有必要結合使用幾種不同的方法,具體取決於這種分離的重要性。
剛剛向Michael Aaron Safyan提出了同樣的問題,但在您看來,這些昂貴/涉及的方法對於清晰的代碼維護來說是否現實?還是程序員自律? – flakes
如果您只關心代碼可維護性,程序員紀律就足夠了。 IMO。 –