You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

.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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.19 00:00:29