C# GeneralService类职责梳理及行业最佳实践重构方案咨询
现有类的职责边界问题
当前GeneralService实际同时承担了4类无关联逻辑,完全违反单一职责原则:
- 作为事件订阅者,在构造函数阶段注册全局异常事件总线的监听,实现
IDisposable用于触发事件反订阅 - 作为通用执行封装器,接收传入的任意委托,统一完成执行日志打印、耗时统计、执行耗时落库、执行过程异常捕获与日志记录
- 作为全局异常处理器,接收事件总线推送的异常,完成异常落库、异常处理结果日志打印
- 无意义的依赖中转:同时注入
IServiceProvider、LoggingService、DataService,但依赖使用完全混乱
核心边界模糊的根源:类名GeneralService本身是反模式,没有明确的功能指向,天然会成为后续维护时各种无关逻辑的“垃圾桶”
除了职责拆分问题,现有代码还存在明确的硬伤:
- 依赖使用混乱:构造函数已经注入了
LoggingService,但Execute方法又从IServiceProvider重新拉取一次LoggingService,HandleException方法甚至直接new了一个全新的LoggingService实例,完全没有复用已注入的依赖 - 大量拼写错误:
_logginService拼写缺字符、serviceProvider.getService大小写不规范、StopWatch类名拼写错误、watch.stop()方法名大小写错误、ElapsedMillieseconds多写字符、日志文本存在乱码"Ëxception" - 引入了不必要的服务定位器反模式:类内注入
IServiceProvider用于按需拉取服务,直接破坏了依赖的显式声明特性,既不利于单元测试,也会让类的真实依赖关系隐藏起来
重构落地方案
按照行业通用的单一职责、显式依赖原则,把现有类拆分为两个完全独立的服务:
1. 通用执行封装服务
仅保留Action执行封装的相关逻辑,移除所有事件订阅、反订阅相关代码,命名为ActionExecutionService,职责边界清晰:
public class ActionExecutionService { private readonly LoggingService _loggingService; private readonly DataService _dataService; public ActionExecutionService(LoggingService loggingService, DataService dataService) { _loggingService = loggingService; _dataService = dataService; } public void Execute(Action action) { var stopwatch = new Stopwatch(); stopwatch.Start(); _loggingService.LogInformation("Start Executing action"); try { action(); } catch (Exception exception) { _loggingService.LogException(exception); return; } stopwatch.Stop(); _dataService.CreateLog($"{nameof(ActionExecutionService)} - {nameof(Execute)}: {stopwatch.ElapsedMilliseconds}ms"); } }
这个类的优化点:
- 彻底移除
IServiceProvider依赖,所有需要的服务通过构造函数显式注入 - 全程复用注入的
LoggingService、DataService实例,不存在重复拉取、手动new的情况 - 修正所有拼写、大小写错误
2. 全局异常事件处理服务
仅保留事件订阅、全局异常处理的相关逻辑,命名为GlobalExceptionEventHandler,职责为接收事件总线推送的全局异常,完成异常的持久化存储与处理日志记录:
public class GlobalExceptionEventHandler : IDisposable { private readonly LoggingService _loggingService; private readonly DataService _dataService; private readonly EventBusProvider _eventBusProvider; public GlobalExceptionEventHandler(LoggingService loggingService, DataService dataService, EventBusProvider eventBusProvider) { _loggingService = loggingService; _dataService = dataService; _eventBusProvider = eventBusProvider; _eventBusProvider.RegisterForNotification(this, EventTypes.Exception, HandleException); } private void HandleException(Exception exception) { _dataService.CreateLog(exception); _loggingService.LogInformation("Exception was logged to storage"); } public void Dispose() { _eventBusProvider.UnRegisterForNotification(this); } }
这个类的优化点:
- 直接注入
EventBusProvider,不再通过IServiceProvider按需拉取 - 复用已注入的服务实例,移除手动new
LoggingService的逻辑 - 修正日志乱码问题
通用后续优化规则
- 彻底废弃
GeneralService这类无明确职责指向的命名,所有服务类的命名必须直接对应其核心功能,避免后续维护时无关逻辑随意塞入 - 全面禁用服务定位器反模式:所有类的依赖全部通过构造函数显式声明,不通过
IServiceProvider在类内部按需拉取服务,保证依赖关系透明、可测试 - 统一依赖生命周期管理:
LoggingService、DataService这类基础服务通常注册为单例,注入一次即可全程复用,不允许出现重复拉取、手动创建实例的情况
内容的提问来源于stack exchange,提问作者user10361591
相关产品推荐
相关产品推荐

