天天看点

软件工程:单一职责原则(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 ——————

行动进化自己,输出成就他人

与你一同终身成长

继续阅读