Java中的耦合
一、簡介
在本教程中,我們將學習 Java 中的耦合,包括類型和每個類型的描述。最後,我們簡要介紹了依賴倒置原理和控制倒置以及它們與耦合的關係。
2.Java中的耦合
當我們談論耦合時,我們描述了我們系統中的類相互依賴的程度。我們在開發過程中的目標是減少耦合。
考慮以下場景。我們正在設計一個元數據收集器應用程序。此應用程序為我們收集元數據。它以 XML 格式獲取元數據,然後將獲取的元數據導出到 CSV 文件,僅此而已。正如我們在設計中所理解的那樣,最初的方法可能是:
我們的模塊負責獲取、處理和導出數據。然而,這是一個糟糕的設計。這種設計違反了單一職責原則。因此,為了改進我們的第一個設計,我們需要分離關注點。更改後,我們的設計如下所示:
現在,我們的設計被解耦為兩個新模塊, XML Fetch
和Export CSV
。同時, Metadata Collector Module
依賴於兩者。這種設計比我們最初的方法要好,但它仍在進行中。在接下來的部分中,我們將注意到如何基於良好的耦合實踐來改進我們的設計。
3. 緊耦合
當一組類相互高度依賴,或者我們的類承擔了很多責任時,稱為緊耦合。另一種情況是當一個對象為其使用創建另一個對象時。緊耦合代碼很難維護。
因此,讓我們使用我們的基礎應用程序來看看這種行為。讓我們跳入一些代碼定義。首先,我們的XMLFetch
類:
public class XMLFetch {
public List<Object> fetchMetadata() {
List<Object> metadata = new ArrayList<>();
// Do some stuff
return metadata;
}
}
接下來是CSVExport
類:
public class CSVExport {
public File export(List<Object> metadata) {
System.out.println("Exporting data...");
// Export Metadata
File outputCSV = null;
return outputCSV;
}
}
最後,我們的MetadataCollector
類:
public class MetadataCollector {
private XMLFetch xmlFetch = new XMLFetch();
private CSVExport csvExport = new CSVExport();
public void collectMetadata() {
List<Object> metadata = xmlFetch.fetchMetadata();
csvExport.export(metadata);
}
}
我們可以注意到,我們的MetadataCollector
類依賴於XMLFecth
和CSVExport
類。此外,它還負責創建它們。
如果我們需要改進我們的收集器,可能添加一個新的數據 JSON 提取器並以 PDF 格式導出數據,我們需要在我們的類中包含這些新元素。讓我們編寫新的“改進”類:
public class MetadataCollector {
...
private CSVExport csvExport = new CSVExport();
private PDFExport pdfExport = new PDFExport();
public void collectMetadata(int inputType, int outputType) {
if (outputType == 1) {
List<Object> metadata = null;
if (inputType == 1) {
metadata = xmlFetch.fetchMetadata();
} else {
metadata = jsonFetch.fetchMetadata();
}
csvExport.export(metadata);
} else {
List<Object> metadata = null;
if (inputType == 1) {
metadata = xmlFetch.fetchMetadata();
} else {
metadata = jsonFetch.fetchMetadata();
}
pdfExport.export(metadata);
}
}
}
Metadata Collector Module
需要一些標誌來處理新功能。根據標誌值,將實例化相應的子模塊。然而,每一個新功能不僅使我們的代碼更加複雜,而且使維護更加困難。這是緊耦合的標誌,我們必須避免它。
4. 松耦合
在開發過程中,我們所有類之間的關係數量需要盡可能少。這稱為鬆散耦合。鬆散耦合是當一個對像從外部源獲取要使用的對象時。我們的對象彼此獨立。鬆散耦合的代碼減少了維護工作。此外,它為系統提供了更大的靈活性。
鬆散耦合是通過依賴倒置原則來表達的。在下一節中,我們將對其進行描述。
5.依賴倒置原則
依賴倒置原則(DIP)是指高層模塊不應該依賴低層模塊來完成它們的職責。兩者都應該依賴於抽象。
在我們的設計中,這是根本問題。元數據收集器(高級)模塊依賴於獲取 XML 和導出 CSV 數據(低級)模塊。
但是我們能做些什麼來改進我們的設計呢? DIP 向我們展示了解決方案,但它沒有談論如何實現它。在這種情況下,正是控制反轉 (IoC) 採取行動的時候。 IoC 指示了在我們的模塊之間定義抽象的方式。綜上所述,就是實現DIP的方式。
因此,讓我們將 DIP 和 IoC 應用到我們當前的示例中。首先,我們需要定義一個用於獲取數據的接口和其他用於導出數據的接口。讓我們跳到代碼中,看看如何做到這一點:
public interface FetchMetadata {
List<Object> fetchMetadata();
}
很簡單,不是嗎?現在我們定義我們的導出接口:
public interface ExportMetadata {
File export(List<Object> metadata);
}
此外,我們需要在對應的類中實現這些接口。簡而言之,我們需要更新我們當前的類:
public class XMLFetch implements FetchMetadata {
@Override
public List<Object> fetchMetadata() {
List<Object> metadata = new ArrayList<>();
// Do some stuff
return metadata;
}
}
接下來,我們需要更新CSVExport
類:
public class CSVExport implements ExportMetadata {
@Override
public File export(List<Object> metadata) {
System.out.println("Exporting data...");
// Export Metadata
File outputCSV = null;
return outputCSV;
}
}
此外,我們更新了主模塊的代碼以支持新的設計更改。讓我們看看它的外觀:
public class MetadataCollector {
private FetchMetadata fetchMetadata;
private ExportMetadata exportMetadata;
public MetadataCollector(FetchMetadata fetchMetadata, ExportMetadata exportMetadata) {
this.fetchMetadata = fetchMetadata;
this.exportMetadata = exportMetadata;
}
public void collectMetadata() {
List<Object> metadata = fetchMetadata.fetchMetadata();
exportMetadata.export(metadata);
}
}
我們可以觀察到代碼中的兩個主要變化。首先,類只依賴於抽象,而不依賴於具體類型。另一方面,我們消除了對低級模塊的依賴。無需在收集器模塊中保留任何與低級模塊創建相關的邏輯。與這些模塊的交互是通過標準接口進行的。這種設計的優點是我們可以添加新的模塊來獲取和導出數據,並且我們的收集器代碼不會改變。
通過應用 DIP 和 IoC,我們改進了系統設計。通過反轉(更改)控件,應用程序變得解耦、可測試、可擴展和可維護。下圖向我們展示了當前設計的外觀:
最後,我們從代碼庫中刪除任何緊密耦合的代碼,並使用帶有 IoC 的 DIP 使用鬆散耦合的代碼來增強初始設計。
六,結論
在本文中,我們介紹了 Java 中的耦合。我們首先介紹了一般耦合定義。然後,我們觀察了緊耦合和松耦合之間的差異。後來,我們學會了將 DIP 與 IoC 一起使用,以獲得鬆散耦合的代碼。此演練是通過遵循示例設計完成的。我們可以通過應用良好的設計模式來觀察我們的代碼在每一步中是如何改進的。
像往常一樣,我們的代碼可以在 GitHub 上找到。