关于理解单一职责原则(SRP)的技术咨询(附实例)
单一职责原则(SRP)疑问解答
问题1:GetListOfTables方法内置空文件夹验证是否违反SRP?
结论:确实违反了单一职责原则
单一职责原则的核心是:一个方法(或类)只应该有一个引起它变化的原因。当前的GetListOfTables承担了两个完全独立的职责:
- 从指定目录获取CSV文件名称列表(文件系统操作职责)
- 处理空列表场景下的用户交互(提示信息、等待回车输入的UI交互职责)
这两个职责的变化原因完全分离:比如未来你可能需要修改文件获取的规则(比如从其他目录读取、过滤特定前缀的文件),或者修改提示文案、等待的触发按键——这两类修改互不相关,却都需要改动同一个方法,这就违反了SRP。
你提到“未来无需修改验证逻辑”,但SRP的判断依据不是“会不会改”,而是“是否存在独立的变化维度”。即使现在不需要修改,拆分职责也能带来这些好处:
- 代码复用性提升:如果其他场景只需要获取CSV列表,不需要等待用户输入,拆分后的方法可以直接复用
- 可测试性提升:单独测试文件列表获取逻辑时,不需要处理用户交互的模拟
- 代码可读性提升:每个方法的职责清晰,其他开发者一眼就能看懂
重构示例:
// 仅负责获取CSV文件列表 public static List<string> GetCsvFileList() { return Directory .GetFiles(".", "*.csv") .Select(file => Path.GetFileName(file)) .ToList(); } // 仅负责处理空文件列表的用户交互 public static void WaitForValidCsvFiles() { var tables = GetCsvFileList(); while (tables.Count == 0) { Output.Invoke("No .csv files are found, please put a table csv file in the program folder and press <Enter> to continue"); while (Console.ReadKey(true).Key != ConsoleKey.Enter) { } tables = GetCsvFileList(); } } // 原业务逻辑调用方式 WaitForValidCsvFiles(); var tables = GetCsvFileList();
如果需要保持原方法的对外接口,可以让GetListOfTables内部组合这两个方法,既兼容原有调用,又实现职责拆分。
问题2:CsvParser类包含GetListOfTables是否违反SRP?
结论:违反了单一职责原则
CsvParser的核心职责是“将CSV文件解析为对象列表”,而GetListOfTables属于“定位/获取CSV文件资源”的职责,这两个职责完全独立:
- 解析逻辑的变化(比如修改字段映射规则、支持不同CSV格式)和文件列表的获取逻辑无关
- 文件列表的获取逻辑变化(比如从云存储、数据库获取文件路径)也和解析逻辑无关
即使当前工具类很小,拆分后依然能带来长期收益:
- 职责边界清晰:新开发者一看就知道
CsvParser只负责解析,文件定位有专门的类处理 - 扩展性更好:未来修改文件获取方式时,不需要改动解析类的代码
- 代码更易维护:每个类的代码量更少,排查问题时范围更小
重构示例:
// 专门负责CSV文件定位的类 static class CsvFileLocator { public static List<string> GetListOfTables() { return Directory .GetFiles(".", "*.csv") .Select(file => Path.GetFileName(file)) .ToList(); } } // 专注于CSV解析的类 static class CsvParser { public static List<List<object>> GetTable(string tableName) { // 这里实现CSV解析为对象列表的逻辑 } }
作为编程新手,不用过度担心“拆分过度”——单一职责原则的本质是帮你建立清晰的代码边界,养成这个习惯后,后续维护和扩展代码会轻松很多。
内容的提问来源于stack exchange,提问作者Humble Newbie
相关产品推荐
相关产品推荐

