.NET中同一类部分方法多实现的最优设计模式方案咨询
最优实现方案咨询
现有代码实现
IMyDataService 实现类
public class MyDataService: IMyDataService { // 先将这两个方法改为virtual,方便后续重写 public virtual void Method1() { // 从外部服务获取数据 } public virtual void Method2() { // 从外部服务获取数据 } public void CommonMethodA() { // 获取数据} public void CommonMethodB() { // 获取数据 } public void CommonMethodC() { // 获取数据 } // 其他方法... }
MyManager 与 Calculator1
public class MyManager { private readonly IMyDataService _myservice; // 构造函数注入依赖 public MyManager(IMyDataService myservice) { _myservice = myservice; } public void DoComplexCalculations() { _myservice.CommonMethodA(); _myservice.CommonMethodB(); _myservice.Method1(); } } public class Calculator1 { private readonly MyManager _mymanager; public Calculator1(MyManager mymanager) { _mymanager = mymanager; } public void Do() { _mymanager.DoComplexCalculations(); } }
需求说明
- 同一解决方案的另一个项目中,
Calculator2需要调用MyManager.DoComplexCalculations方法 - 要求该场景下
Method1和Method2改用缓存实现(调用FromCacheMethod1和FromCacheMethod2),其余通用方法逻辑保持不变 - 所需缓存数据已在调用前准备完成
当前方案的问题
- 装饰器模式:需要手动实现所有通用方法的转发代码,冗余且不符合装饰器“动态添加功能”的核心适用场景
- 修改原有方法加缓存:直接改动原有业务逻辑,违反开闭原则,容易引入问题且不利于维护
推荐实现方案
方案一:继承重写 + 区分依赖注入(优先推荐,改动最小)
1. 创建缓存版数据服务
继承原MyDataService,只重写需要替换的Method1和Method2,其余通用方法直接复用父类逻辑:
public class CachedMyDataService : MyDataService { public override void Method1() { // 替换为缓存读取逻辑 FromCacheMethod1(); } public override void Method2() { // 替换为缓存读取逻辑 FromCacheMethod2(); } private void FromCacheMethod1() { /* 从缓存获取数据的逻辑 */ } private void FromCacheMethod2() { /* 从缓存获取数据的逻辑 */ } }
2. 配置依赖注入
在Startup中注册两个版本的服务,分别供不同场景使用:
// 原有服务,给Calculator1使用 services.AddScoped<IMyDataService, MyDataService>(); // 缓存版服务,给Calculator2对应的Manager使用 services.AddScoped<CachedMyDataService>();
3. 为Calculator2配置专属Manager
可以创建一个继承自MyManager的子类,注入缓存版服务:
public class CachedMyManager : MyManager { public CachedMyManager(CachedMyDataService myservice) : base(myservice) { } } // 注册CachedMyManager services.AddScoped<CachedMyManager>(); // Calculator2实现 public class Calculator2 { private readonly CachedMyManager _cachedMyManager; public Calculator2(CachedMyManager cachedMyManager) { _cachedMyManager = cachedMyManager; } public void Do() { _cachedMyManager.DoComplexCalculations(); } }
如果不想新增Manager类,也可以通过命名服务的方式注册不同的MyManager实例,在Calculator2中指定获取缓存版对应的实例。
方案二:策略模式(适合未来有更多扩展需求)
如果后续可能出现更多数据获取方式(比如数据库、第三方接口等),可以用策略模式解耦数据获取逻辑:
1. 定义数据获取策略接口
public interface IDataFetchStrategy { void Method1(); void Method2(); }
2. 实现两种策略
// 原有外部服务策略 public class ExternalServiceStrategy : IDataFetchStrategy { public void Method1() { /* 从外部服务获取数据 */ } public void Method2() { /* 从外部服务获取数据 */ } } // 缓存策略 public class CacheFetchStrategy : IDataFetchStrategy { public void Method1() { FromCacheMethod1(); } public void Method2() { FromCacheMethod2(); } private void FromCacheMethod1() { /* 缓存读取逻辑 */ } private void FromCacheMethod2() { /* 缓存读取逻辑 */ } }
3. 修改MyDataService,注入策略
public class MyDataService: IMyDataService { private readonly IDataFetchStrategy _fetchStrategy; public MyDataService(IDataFetchStrategy fetchStrategy) { _fetchStrategy = fetchStrategy; } public void Method1() => _fetchStrategy.Method1(); public void Method2() => _fetchStrategy.Method2(); // 通用方法保持不变 public void CommonMethodA() { /* 原有逻辑 */ } public void CommonMethodB() { /* 原有逻辑 */ } // ...其他方法 }
4. 配置DI,为不同场景注入不同策略
// 给Calculator1的Manager注入外部服务策略 services.AddScoped<MyManager>(sp => new MyManager(new MyDataService(sp.GetRequiredService<ExternalServiceStrategy>()))); // 给Calculator2的Manager注入缓存策略 services.AddScoped<MyManager>(sp => new MyManager(new MyDataService(sp.GetRequiredService<CacheFetchStrategy>())));
方案选择建议
- 如果当前只有“外部服务”和“缓存”两种场景,**方案一(继承重写)**更简洁,改动量最小,对原有代码侵入性低
- 如果未来可能扩展更多数据获取方式,**方案二(策略模式)**更灵活,符合单一职责原则,便于后续维护和扩展
内容的提问来源于stack exchange,提问作者renathy
相关产品推荐
相关产品推荐

