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

如何优化枚举检查与仓储方法调用?SOLID开闭原则合规方案

这个问题我之前也碰到过——用switch处理多类型分支确实会违反开闭原则,每次新增ReturnType都得修改原有的switch块,维护起来特别麻烦。你想到用字典映射的思路是完全正确的,只是需要调整一下来适配不同的返回类型,下面给你两个实用的解决方案:

方案一:策略模式+泛型接口(推荐,更符合SOLID)

这种方式通过抽象出数据获取的通用接口,把每个类型的逻辑封装到独立的类中,完美遵循开闭原则。

首先定义一个通用的数据提供接口:

public interface IDataProvider<T>
{
    IEnumerable<T> GetData();
}

然后为每个ReturnType实现对应的提供类,比如HR类型:

public class HRDataProvider : IDataProvider<HR>
{
    private readonly IRepo _repo;

    // 通过构造注入仓储实例
    public HRDataProvider(IRepo repo) => _repo = repo;

    public IEnumerable<HR> GetData() => _repo.GetSystemManuals();
}

同理,为Finance、Dev等类型实现对应的IDataProvider:

public class FinanceDataProvider : IDataProvider<PrivateRecord>
{
    private readonly IRepo _repo;

    public FinanceDataProvider(IRepo repo) => _repo = repo;

    public IEnumerable<PrivateRecord> GetData() => _repo.GetPrivateRecords();
}

// 其他类型的Provider以此类推...

接下来在你的业务类中,创建ReturnType到IDataProvider实例的映射字典:

public class YourBusinessService
{
    private readonly IDictionary<ReturnType, object> _providerMap;

    public YourBusinessService(IRepo repo)
    {
        _providerMap = new Dictionary<ReturnType, object>
        {
            { ReturnType.HR, new HRDataProvider(repo) },
            { ReturnType.Finance, new FinanceDataProvider(repo) },
            { ReturnType.Dev, new DevDataProvider(repo) },
            { ReturnType.Admin, new AdminDataProvider(repo) },
            { ReturnType.Support, new SupportDataProvider(repo) }
        };
    }

    // 通用的获取数据方法
    public IEnumerable<T> GetData<T>(ReturnType returnType)
    {
        if (_providerMap.TryGetValue(returnType, out var provider) && provider is IDataProvider<T> dataProvider)
        {
            return dataProvider.GetData();
        }

        throw new ArgumentOutOfRangeException(nameof(returnType), $"不支持的返回类型:{returnType}");
    }
}

调用的时候只需要明确指定返回类型即可:

var hrData = service.GetData<HR>(ReturnType.HR);
var financeData = service.GetData<PrivateRecord>(ReturnType.Finance);

以后新增ReturnType时,只需要新增对应的IDataProvider实现,然后在字典里加一条映射即可,完全不需要修改原有逻辑,完美符合开闭原则。

方案二:简化版——用Func委托字典(快速实现,适合简单场景)

如果不想创建太多Provider类,可以直接用字典存储返回不同类型的委托,通过泛型方法做类型转换:

public class YourBusinessService
{
    private readonly IDictionary<ReturnType, Func<object>> _dataGetterMap;

    public YourBusinessService(IRepo repo)
    {
        _dataGetterMap = new Dictionary<ReturnType, Func<object>>
        {
            { ReturnType.HR, () => repo.GetSystemManuals() },
            { ReturnType.Finance, () => repo.GetPrivateRecords() },
            { ReturnType.Dev, () => repo.GetTimeLine() },
            { ReturnType.Admin, () => repo.GetLedger() },
            { ReturnType.Support, () => repo.GetRoster() }
        };
    }

    public IEnumerable<T> GetData<T>(ReturnType returnType)
    {
        if (_dataGetterMap.TryGetValue(returnType, out var getter))
        {
            var result = getter();
            if (result is IEnumerable<T> typedResult)
            {
                return typedResult;
            }

            throw new InvalidCastException($"返回类型无法转换为IEnumerable<{typeof(T).Name}>");
        }

        throw new ArgumentOutOfRangeException(nameof(returnType));
    }
}

这种方式代码量更少,适合逻辑简单的场景,但扩展性比策略模式稍弱——新增类型时还是要修改字典的初始化代码(不过相比switch,修改范围更小,也更清晰)。

关键说明

两种方案的核心都是把分支逻辑从switch转移到外部映射,这样新增类型时不需要修改原有分支判断代码,只需要扩展映射内容,从而遵循开闭原则。如果你的项目用了依赖注入框架,还可以把所有IDataProvider实例注册到容器中,然后通过容器动态获取,进一步减少硬编码的映射。

内容的提问来源于stack exchange,提问作者Simsons

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 04:16:03