天天看點

軟體工程:單一職責原則(SRP)

作者:熵減黑客
軟體工程:單一職責原則(SRP)

hi,我是熵減,見字如面。

在開發軟體時,通常會面臨一個問題:如何設計類和子產品,使其易于了解、修改和維護?

這就需要我們遵循一些設計原則,其中單一職責原則(SRP)是其中之一。

單一職責原則的核心思想是一個類或子產品隻應該有一個職責,即一個類或子產品隻負責一項功能。

這個原則是面向對象設計中最重要的原則之一,它可以提高代碼的可讀性、可維護性和可擴充性。

今天,我們将深入探讨單一職責原則,以及如何在實際開發中遵循這個原則。

Part1什麼是單一職責?

單一職責原則(Single Responsibility Principle,簡稱 SRP)是指一個子產品或類隻應該負責單一的功能或責任。換句話說,一個類或子產品應該隻有一個引起它變化的原因。

SRP 是面向對象設計的一個基本原則,它可以提高代碼的可維護性、可讀性、可擴充性和可重用性。

如果一個子產品或類負責過多的功能,那麼它會變得複雜、難以了解和難以修改。

相反,如果一個子產品或類隻負責一個功能,那麼它的職責就更加清晰明确,容易被了解和維護。

SRP 還可以幫助開發人員更好地組織代碼結構,使其更加子產品化和靈活。

通過将不同的職責分離成不同的類或子產品,可以使得代碼更易于擴充和修改,也更容易進行測試和重用。

Part2 一個案例

以下是一個簡單的 Java 代碼示例,示範了如何逐漸應用單一職責原則,來改進代碼設計。

1 初始版本

首先是一個最初的版本,這個版本的代碼實作了一個簡單的功能:讀取一個檔案并将其中的内容轉換為字元串。

但是,這個版本的代碼職責過于複雜,既包含了檔案操作,也包含了字元串操作,違反了單一職責原則。具體代碼如下:

public class FileReader {
    
    public String readFromFile(String filename) throws IOException {
        File file = new File(filename);
        BufferedReader br = new BufferedReader(new FileReader(file));
        StringBuilder sb = new StringBuilder();
        String line;
        while ((line = br.readLine()) != null) {
            sb.append(line);
        }
        br.close();
        return sb.toString();
    }
}

           

2 改進版

接下來,我們可以使用單一職責原則來改進這個代碼:将其拆分為兩個類,每個類隻負責一項職責。具體代碼如下:

public class FileReader {
    
    public String readFromFile(String filename) throws IOException {
        File file = new File(filename);
        BufferedReader br = new BufferedReader(new FileReader(file));
        StringBuilder sb = new StringBuilder();
        String line;
        while ((line = br.readLine()) != null) {
            sb.append(line);
        }
        br.close();
        return sb.toString();
    }
}

public class StringConverter {
    
    public String convertToString(String input) {
        // some logic to convert the input string
        return convertedString;
    }
}

           

在這個版本中,FileReader 類負責從檔案中讀取資料,StringConverter 類負責将字元串轉換為其他形式。這兩個類各自負責不同的職責,遵循了單一職責原則。

3 依賴注入版

我們可以進一步改進這個代碼,使用依賴注入來解耦代碼。通過使用接口和依賴注入,可以使得這兩個類更加靈活和可擴充。具體代碼如下:

public interface Reader {
    public String read();
}

public interface Converter {
    public String convert(String input);
}

public class FileReader implements Reader {
    
    public String read() throws IOException {
        // read from file
    }
}

public class StringConverter implements Converter {
    
    public String convert(String input) {
        // some logic to convert the input string
        return convertedString;
    }
}

public class DataProcessor {
    
    private Reader reader;
    private Converter converter;
    
    public DataProcessor(Reader reader, Converter converter) {
        this.reader = reader;
        this.converter = converter;
    }
    
    public String processData() throws IOException {
        String data = reader.read();
        return converter.convert(data);
    }
}

           

在這個版本中,我們将 FileReader 和 StringConverter 分别抽象成了 Reader 和 Converter 接口,并通過依賴注入的方式注入到 DataProcessor 類中。

這種方式使得代碼更加靈活、可擴充和易于測試,同時也更好地遵循了單一職責原則。

Part3 最佳實踐

在我們日常的系統設計和開發中,有哪些舉措可以更好的實作單一職責的原則呢?

以下是一些單一職責原則落地的最佳實踐經驗:

  • 将類或子產品的職責盡可能地降到最小。一個類或子產品的職責應該越單一越好,盡量避免實作多個功能。
  • 如果一個類或子產品負責的職責太多,可以考慮拆分成多個類或子產品,每個類或子產品隻負責單一的職責。
  • 在拆分職責的過程中,要考慮職責的相關性,将相關的職責放到同一個類或子產品中,減少耦合度。
  • 避免在一個類或子產品中實作與職責無關的功能。
  • 将通用的功能封裝成獨立的類或子產品,并在需要時進行調用,避免重複實作。
  • 要注意職責的界限,避免将與職責無關的代碼放到同一個類或子產品中。
  • 在設計時要考慮未來的需求變化,将可擴充性考慮進去,保證代碼的可維護性。
  • 在實作時要注意代碼的可讀性,使用有意義的變量名和函數名,以及清晰的代碼結構。
  • 在測試時要考慮職責的獨立性,對于每個職責都進行單獨的測試,確定代碼的正确性和穩定性。

總之,在實際開發中,我們應該盡可能地遵循這個原則,并注意一些最佳實踐,以達到更好的設計效果。

Part4 反模式

單一職責原則是面向對象設計中的一個重要原則,它要求一個類或子產品隻負責一項職責。但是在實踐中,我們也會遇到一些反模式,下面是單一職責原則的常見反模式:

過度拆分

過度拆分是指在拆分類或子產品時過度細化,導緻代碼過于分散,增加了代碼的複雜性和維護難度。在設計時,應該權衡好單一職責原則和代碼的複雜性,避免過度拆分。

職責不清

職責不清是指類或子產品的職責不夠明确,導緻代碼難以維護和擴充。在設計時,應該明确類或子產品的職責,避免職責模糊不清。

任務超出職責範圍

任務超出職責範圍是指類或子產品承擔了超出其職責範圍的任務,導緻代碼的耦合性增加,難以維護和擴充。在設計時,應該明确類或子產品的職責範圍,避免任務超出職責範圍。

職責沖突

職責沖突是指類或子產品承擔的職責之間存在沖突,導緻代碼難以維護和擴充。在設計時,應該避免職責之間的沖突,確定類或子產品的職責清晰明确。

依賴過度

依賴過度是指類或子產品依賴于其他類或子產品,導緻代碼的耦合性增加,難以維護和擴充。

在設計時,應該盡量減少類或子產品之間的依賴關系,提高代碼的靈活性和可擴充性。

為了避免這些反模式,開發人員應該遵循單一職責原則的原則,確定類或子產品的職責明确,避免任務超出職責範圍,避免職責沖突,盡量減少依賴關系,提高代碼的靈活性和可擴充性。

Part5 最後

單一職責原則是面向對象設計中的一個重要原則,它要求一個類或子產品隻負責一項職責。

遵循單一職責原則可以提高代碼的靈活性和可擴充性,使代碼更易于維護和修改。

同時,開發人員也應該避免違反單一職責原則的反模式,并盡可的參考一些最佳的實踐。

總之,通過遵循單一職責原則和避免其反模式,可以有效地提高代碼的品質和可維護性。

—————— THE END ——————

行動進化自己,輸出成就他人

與你一同終身成長

繼續閱讀