C#中不同枚举类型的同逻辑方法优化设计模式咨询
针对C#枚举重载方法逻辑重复的优化方案
你的核心问题是两个逻辑完全一致的异步泛型方法,因依赖无继承关系的枚举导致代码重复,且需判断不同枚举的特定值执行相同后端逻辑。以下是几种适配C#特性的优化方案:
方案1:提取核心逻辑+传递判断委托(最简方案)
直接将重复逻辑抽离到私有泛型方法,通过委托传入不同枚举的判断规则,快速消除代码冗余。
// 对外暴露的重载方法 public async Task<T> Foo<T>(string id, IList<UserSettingType> settings, Func<IMyService, Task<T>> backendFunc) { return await FooCore(id, settings, s => s == UserSettingType.Permission, backendFunc); } public async Task<T> Foo<T>(string id, IList<TeamsSettingType> settings, Func<IMyService, Task<T>> backendFunc) { return await FooCore(id, settings, s => s == TeamsSettingType.PermissionPolicy, backendFunc); } // 公共核心逻辑,泛型适配任意枚举类型 private async Task<T> FooCore<T, TSetting>(string id, IList<TSetting> settings, Func<TSetting, bool> shouldTrigger, Func<IMyService, Task<T>> backendFunc) { // 原重复逻辑统一实现 foreach (var setting in settings) { if (shouldTrigger(setting)) { return await backendFunc(_myService); } } // 其他通用逻辑 return default; }
优点:实现简单,无额外类型定义,快速解决重复问题;缺点:新增枚举时需新增重载方法。
方案2:适配器模式(适配异构枚举)
将无继承关系的枚举适配为统一的抽象接口,让核心逻辑仅处理抽象类型,符合开闭原则。
- 定义抽象接口:
public interface ISetting { bool ShouldTriggerBackend(); }
- 为每个枚举实现适配器:
public class UserSettingAdapter : ISetting { private readonly UserSettingType _setting; public UserSettingAdapter(UserSettingType setting) => _setting = setting; public bool ShouldTriggerBackend() => _setting == UserSettingType.Permission; } public class TeamsSettingAdapter : ISetting { private readonly TeamsSettingType _setting; public TeamsSettingAdapter(TeamsSettingType setting) => _setting = setting; public bool ShouldTriggerBackend() => _setting == TeamsSettingType.PermissionPolicy; }
- 重构核心方法:
public async Task<T> Foo<T>(string id, IList<UserSettingType> settings, Func<IMyService, Task<T>> backendFunc) { var adaptedSettings = settings.Select(s => new UserSettingAdapter(s)).ToList(); return await FooCore(id, adaptedSettings, backendFunc); } public async Task<T> Foo<T>(string id, IList<TeamsSettingType> settings, Func<IMyService, Task<T>> backendFunc) { var adaptedSettings = settings.Select(s => new TeamsSettingAdapter(s)).ToList(); return await FooCore(id, adaptedSettings, backendFunc); } private async Task<T> FooCore<T>(string id, IList<ISetting> settings, Func<IMyService, Task<T>> backendFunc) { foreach (var setting in settings) { if (setting.ShouldTriggerBackend()) { return await backendFunc(_myService); } } // 其他通用逻辑 return default; }
优点:新增枚举仅需添加对应适配器,核心逻辑无需修改;缺点:需额外定义适配器类,代码量略增。
方案3:策略模式(解耦判断逻辑)
将不同枚举的判断逻辑封装为独立策略,核心方法依赖策略接口,进一步解耦判断规则与业务逻辑。
- 定义策略接口:
public interface ISettingTriggerStrategy<TSetting> { bool ShouldTrigger(TSetting setting); }
- 实现枚举专属策略:
public class UserSettingTriggerStrategy : ISettingTriggerStrategy<UserSettingType> { public bool ShouldTrigger(UserSettingType setting) => setting == UserSettingType.Permission; } public class TeamsSettingTriggerStrategy : ISettingTriggerStrategy<TeamsSettingType> { public bool ShouldTrigger(TeamsSettingType setting) => setting == TeamsSettingType.PermissionPolicy; }
- 重构核心方法:
public async Task<T> Foo<T>(string id, IList<UserSettingType> settings, Func<IMyService, Task<T>> backendFunc) { return await FooCore(id, settings, new UserSettingTriggerStrategy(), backendFunc); } public async Task<T> Foo<T>(string id, IList<TeamsSettingType> settings, Func<IMyService, Task<T>> backendFunc) { return await FooCore(id, settings, new TeamsSettingTriggerStrategy(), backendFunc); } private async Task<T> FooCore<T, TSetting>(string id, IList<TSetting> settings, ISettingTriggerStrategy<TSetting> triggerStrategy, Func<IMyService, Task<T>> backendFunc) { foreach (var setting in settings) { if (triggerStrategy.ShouldTrigger(setting)) { return await backendFunc(_myService); } } // 其他通用逻辑 return default; }
优点:判断逻辑完全独立,可单独修改或替换;缺点:需定义多个策略类,适合判断规则复杂或易变的场景。
方案4:标记接口+扩展方法(简洁适配)
通过标记接口约束枚举,结合扩展方法统一处理判断逻辑,兼顾简洁性与一定扩展性。
- 定义标记接口:
public interface ISettingEnum { }
- 让枚举实现标记接口:
public enum UserSettingType : byte, ISettingEnum { // 其他枚举值 Permission } public enum TeamsSettingType : byte, ISettingEnum { // 其他枚举值 PermissionPolicy }
- 编写扩展方法实现判断:
public static class SettingEnumExtensions { public static bool ShouldTriggerBackend(this ISettingEnum setting) { return setting switch { UserSettingType us => us == UserSettingType.Permission, TeamsSettingType ts => ts == TeamsSettingType.PermissionPolicy, _ => false }; } }
- 重构核心方法:
public async Task<T> Foo<T>(string id, IList<UserSettingType> settings, Func<IMyService, Task<T>> backendFunc) { return await FooCore(id, settings.Cast<ISettingEnum>().ToList(), backendFunc); } public async Task<T> Foo<T>(string id, IList<TeamsSettingType> settings, Func<IMyService, Task<T>> backendFunc) { return await FooCore(id, settings.Cast<ISettingEnum>().ToList(), backendFunc); } private async Task<T> FooCore<T>(string id, IList<ISettingEnum> settings, Func<IMyService, Task<T>> backendFunc) { foreach (var setting in settings) { if (setting.ShouldTriggerBackend()) { return await backendFunc(_myService); } } // 其他通用逻辑 return default; }
优点:无需额外类,代码简洁;缺点:新增枚举需修改扩展方法的switch分支,不符合开闭原则,适合枚举类型稳定的场景。
内容的提问来源于stack exchange,提问作者Programmerzzz
相关产品推荐
相关产品推荐

