C# 去除if-else以及子类管理 (中)利用特性限制策略条件

本文介绍如何通过特性来改进策略模式中的策略选择机制,避免使用if-else语句,实现更灵活的策略筛选。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

上一篇我们完成了策略模式以及工厂模式的添加,已经成功将策略的选择从消费者中分离出来,但是在工厂中仍然需要使用if else进行策略的筛选,为了解决这个问题我们引入一些新的东西:特性。

特性大家可以理解为和属性差不多的东西,特性本质是一个类,可以给其他的对象赋予属性。这里我不对特性进行过多说明,大家可以参考https://blog.youkuaiyun.com/long2006sky/article/details/1629075

在我们这次的例子中是以价格作为筛选策略的条件,也就是所每一个策略都拥有自己的价格区间,那么我们可以利用特性进行区间的限定操作,我们编写一个价格区间的特性类。

[AttributeUsage(AttributeTargets.Class)]//限定由于修饰类
public class PriceAttribute : Attribute
{
    public float Max { private set; get; }
    public float Min { private set; get; }

    public PriceAttribute(int min = -1, int max = 999999)
    {
        Max = max;
        Min = min;
    }
}

有了这个我们就可以给每一个策略添加上下限的特性

[Price(0,1000)]//特性命名中的Attribute可以省略
public class PublicVipStrategy : IVipStrategy
{
    public float GetExtenditure(float price)
    {
        return price;
    }
}

[Price(1000,2000)]
public class JuniorVipStrategy : IVipStrategy
{
    public float GetExtenditure(float price)
    {
        return price * 0.9f;
    }
}

策略拥有了特性之后我们在工厂中对特性进行读取

using System;

public class VipStrategyFactory
{
    private static VipStrategyFactory _instance;

    public static VipStrategyFactory Instance
    {
        get
        {
            if (_instance == null)
                _instance = new VipStrategyFactory();
            return _instance;
        }
    }

    //改写获取方法,利用特性筛选
    public IVipStrategy GetVipStrategy(Consumer consumer)
    {
        var totalConsume = consumer.TotalConsume;
        Type[] types =
        {
            typeof(PublicVipStrategy),
            typeof(JuniorVipStrategy)
        };
        foreach (var type in types)
        {
            var att = GetAttribute(type);
            if (att == null) continue;
            if ((att.Min <= totalConsume) && (totalConsume < att.Max))
                return (IVipStrategy) Activator.CreateInstance(type);
        }
        return new PublicVipStrategy();
    }

    private PriceAttribute GetAttribute(Type t)
    {
        var atts = t.GetCustomAttributes(typeof(PriceAttribute), true);
        if ((atts == null) || (atts.Length <= 0)) return null;
        foreach (PriceAttribute att in atts)
        {
            return att;
        }
        return null;
    }
}

改写完成以后我们可以看到已经去除掉if else的选择了,会根据特性区间进行自动筛选策略。如果需要添加新的Vip策略,直接继承基类,并且赋予特性区间范围即可。如高级会员

[Price(2000, 3000)]
public class SeniorVipStrategy : IVipStrategy
{
    public float GetExtenditure(float price)
    {
        return price*0.8f;
    }
}

注意修改工厂中Type数组,添加该会员的类型

        Type[] types =
        {
            typeof(PublicVipStrategy),
            typeof(JuniorVipStrategy),
            typeof(SeniorVipStrategy)
        };

我们看下消费情况

namespace Assets.Demo01.Strategy
{
    public class ContextView
    {
        public void Main()
        {
            var consumer = new Consumer();
            consumer.Buy(1000);
            consumer.Buy(1000);
            consumer.Buy(1000);
        }
    }
}

这里我们看到我们准备分三次购买价值1000金的商品,第二次我们是初级会员打折扣了,第三次的时候为什么没有打折扣呢,看程序,第二次我们实际只消费的900元,也就是目前共消费1900元,仍然处于初级会员状态,所以下一次消费仍然是900,我们想要第三次消费可以享受高级会员的优惠,可以适当提高第二次的消费如

namespace Assets.Demo01.Strategy
{
    public class ContextView
    {
        public void Main()
        {
            var consumer = new Consumer();
            consumer.Buy(1000);
            consumer.Buy(2000);
            consumer.Buy(2800);
        }
    }
}

第三次成功享受八折优惠。

目前为止已经完成70%,为什么呢,因为我们发现区间的问题很好解决,甚至使用属性就可以。但是新增加的策略需要修改工厂进行添加类型,这样就不符合我们的开闭原则,所以我们在下章解决该问题。

转载请标明出处。

<think>我们正在优化C#代码中大量的if-else条件判断,目标是减少代码复杂度,提高可读性和可维护性。根据引用内容,我们可以采用以下几种优化方案: ### 1. 提前return,去除不必要的else块(参考引用[1]) 通过反转条件判断,提前处理特殊情况并返回,从而减少嵌套层级。 **优化前:** ```csharp if (condition) { // 主要逻辑 } else { // 异常处理 } ``` **优化后:** ```csharp if (!condition) { // 异常处理 return; } // 主要逻辑 ``` ### 2. 使用策略模式(参考引用[2]) 将每个分支逻辑封装成独立的策略类,通过字典或工厂模式动态选择策略。 **优化前:** ```csharp if (type == "A") { // 处理A类型 } else if (type == "B") { // 处理B类型 } // ... 更多else if ``` **优化后:** ```csharp // 定义策略接口 public interface IStrategy { void Handle(); } // 具体策略类 public class StrategyA : IStrategy { /* 实现A逻辑 */ } public class StrategyB : IStrategy { /* 实现B逻辑 */ } // 策略工厂 public class StrategyFactory { private Dictionary<string, IStrategy> _strategies = new Dictionary<string, IStrategy> { { "A", new StrategyA() }, { "B", new StrategyB() } }; public IStrategy GetStrategy(string type) { return _strategies.GetValueOrDefault(type); } } // 使用 var strategy = factory.GetStrategy(type); strategy?.Handle(); ``` ### 3. 使用字典映射(参考引用[4]) 对于简单的分支逻辑,可以使用字典将条件映射到对应的处理函数。 **优化前:** ```csharp if (key == "add") return a + b; else if (key == "sub") return a - b; else if (key == "mul") return a * b; ``` **优化后:** ```csharp var operations = new Dictionary<string, Func<int, int, int>> { ["add"] = (a, b) => a + b, ["sub"] = (a, b) => a - b, ["mul"] = (a, b) => a * b }; return operations.TryGetValue(key, out var operation) ? operation(a, b) : 0; ``` ### 4. 使用switch表达式(C# 8.0及以上) C# 8.0引入的switch表达式可以简化分支判断。 **优化前:** ```csharp string result; switch (value) { case 1: result = "one"; break; case 2: result = "two"; break; default: result = "unknown"; break; } ``` **优化后:** ```csharp string result = value switch { 1 => "one", 2 => "two", _ => "unknown" }; ``` ### 5. 使用多态(面向对象设计) 通过继承和多态将条件分支分散到子类中,符合开闭原则。 **优化前:** ```csharp public class Animal { public void Speak(string type) { if (type == "Dog") Console.WriteLine("Woof"); else if (type == "Cat") Console.WriteLine("Meow"); } } ``` **优化后:** ```csharp public abstract class Animal { public abstract void Speak(); } public class Dog : Animal { public override void Speak() => Console.WriteLine("Woof"); } public class Cat : Animal { public override void Speak() => Console.WriteLine("Meow"); } // 使用 Animal animal = GetAnimal(); animal.Speak(); ``` ### 6. 使用状态模式(复杂状态机) 对于状态转换较多的场景,使用状态模式避免大量的条件判断。 **优化前:** ```csharp public class Player { private string _state; public void Update() { if (_state == "Idle") { /* 待机逻辑 */ } else if (_state == "Run") { /* 跑步逻辑 */ } // ... 更多状态 } } ``` **优化后:** ```csharp public interface IState { void Update(Player player); } public class IdleState : IState { public void Update(Player player) { /* 待机逻辑 */ } } public class RunState : IState { public void Update(Player player) { /* 跑步逻辑 */ } } public class Player { private IState _currentState; public void Update() => _currentState.Update(this); } ``` ### 复杂度分析 - **圈复杂度(Cyclomatic Complexity)**:通过上述优化,可以显著降低圈复杂度[^3] - **可维护性**:策略模式和多态设计使代码更符合开闭原则,新增逻辑时只需扩展新类而不修改原有代码 ### 示例:优化用户问题中的代码片段 原问题中的`FixedUpdate`方法包含大量嵌套if-else,我们可以采用策略模式重构: 1. 将每个设备状态处理逻辑封装成独立策略类 2. 构建状态处理管道,按顺序应用策略 3. 使用工厂模式管理策略创建 > **注意**:对于实时性要求高的场景(如游戏循环),需评估策略模式带来的性能开销,通常可忽略不计[^4]。 §§相关问题§§ 1. 策略模式在性能敏感场景下如何优化? 2. 如何度量代码优化前后的圈复杂度变化? 3. C#中还有哪些现代语法可以简化条件判断? 4. 多态设计是否适用于所有条件判断场景?</think># 优化C#中大量if-else条件判断的全面指南 在C#开发中,过度使用if-else语句会增加代码复杂度、降低可读性并难以维护。以下是多种优化策略,结合引用内容提供实用解决方案: ## 1. 提前return策略(参考引用[1]) **核心思想**:尽早处理异常情况,减少嵌套层级 ```csharp // 优化前 public void ProcessOrder(Order order) { if (order != null) { if (order.IsValid) { // 主要业务逻辑... } else { // 处理无效订单 } } } // 优化后 - 提前return public void ProcessOrder(Order order) { if (order == null) return; if (!order.IsValid) return HandleInvalidOrder(order); // 主要业务逻辑... } private void HandleInvalidOrder(Order order) { // 处理无效订单 } ``` ## 2. 策略模式(参考引用[2]) **适用场景**:处理多种业务分支,符合开闭原则 ```csharp // 定义策略接口 public interface IShippingStrategy { decimal CalculateCost(Order order); } // 具体策略实现 public class StandardShipping : IShippingStrategy { /* 实现 */ } public class ExpressShipping : IShippingStrategy { /* 实现 */ } public class InternationalShipping : IShippingStrategy { /* 实现 */ } // 策略工厂 public class ShippingFactory { private static readonly Dictionary<string, IShippingStrategy> _strategies = new Dictionary<string, IShippingStrategy> { ["Standard"] = new StandardShipping(), ["Express"] = new ExpressShipping(), ["International"] = new InternationalShipping() }; public static IShippingStrategy GetStrategy(string type) { return _strategies.TryGetValue(type, out var strategy) ? strategy : throw new ArgumentException("Invalid shipping type"); } } // 使用策略 public decimal CalculateShippingCost(Order order) { var strategy = ShippingFactory.GetStrategy(order.ShippingType); return strategy.CalculateCost(order); } ``` ## 3. 字典映射(参考引用[4]) **适用场景**:简单键值映射关系 ```csharp // 优化前 public string GetStatusMessage(int statusCode) { if (statusCode == 200) return "OK"; else if (statusCode == 404) return "Not Found"; else if (statusCode == 500) return "Internal Server Error"; // ... } // 优化后 public string GetStatusMessage(int statusCode) { var statusMessages = new Dictionary<int, string> { {200, "OK"}, {404, "Not Found"}, {500, "Internal Server Error"} }; return statusMessages.TryGetValue(statusCode, out var message) ? message : "Unknown Status"; } ``` ## 4. C# 8.0+ Switch表达式 **现代语法**:更简洁的模式匹配 ```csharp public decimal CalculateDiscount(Customer customer) { return customer switch { { MemberLevel: MemberLevel.Gold } => 0.2m, { MemberLevel: MemberLevel.Silver } => 0.1m, { IsFirstOrder: true } => 0.15m, _ => 0m }; } ``` ## 5. 状态模式(复杂状态机) **适用场景**:对象行为随状态改变而改变 ```csharp public interface IOrderState { void Process(Order order); void Cancel(Order order); } public class NewOrderState : IOrderState { /* 实现 */ } public class ProcessingState : IOrderState { /* 实现 */ } public class ShippedState : IOrderState { /* 实现 */ } public class Order { public IOrderState CurrentState { get; set; } public Order() { CurrentState = new NewOrderState(); } public void Process() => CurrentState.Process(this); public void Cancel() => CurrentState.Cancel(this); } ``` ## 6. 责任链模式 **适用场景**:多个处理器处理请求 ```csharp public abstract class Handler { protected Handler _next; public Handler SetNext(Handler next) { _next = next; return next; } public abstract void Handle(Request request); } public class AuthenticationHandler : Handler { /* 实现 */ } public class AuthorizationHandler : Handler { /* 实现 */ } public class ValidationHandler : Handler { /* 实现 */ } // 使用 var chain = new AuthenticationHandler(); chain.SetNext(new AuthorizationHandler()) .SetNext(new ValidationHandler()); chain.Handle(request); ``` ## 7. 使用Func委托 **函数式编程**:将分支逻辑封装为函数 ```csharp public class DiscountCalculator { private static readonly List<Func<Order, decimal?>> _discountRules = new() { order => order.Total > 1000 ? 0.1m : null, order => order.Customer.IsVIP ? 0.15m : null, order => order.Items.Count > 5 ? 0.05m : null }; public decimal CalculateDiscount(Order order) { return _discountRules .Select(rule => rule(order)) .FirstOrDefault(discount => discount.HasValue) ?? 0m; } } ``` ## 复杂度分析与优化效果 | 优化方法 | 圈复杂度降低 | 可维护性提升 | 适用场景 | |---------|-------------|-------------|---------| | 提前return | ★★☆ | ★★☆ | 简单条件判断 | | 策略模式 | ★★★ | ★★★ | 多分支业务逻辑 | | 字典映射 | ★★☆ | ★★☆ | 键值映射关系 | | Switch表达式 | ★★☆ | ★★★ | C# 8.0+ 简单模式匹配 | | 状态模式 | ★★★ | ★★★ | 对象状态变化 | | 责任链 | ★★★ | ★★★ | 请求处理管道 | | Func委托 | ★★☆ | ★★☆ | 规则集合处理 | > 圈复杂度(Cyclomatic Complexity)是衡量代码复杂性的重要指标,每增加一个if-else分支,圈复杂度增加1。理想情况下,单个方法圈复杂度应保持在10以下[^3]。 ## 选择优化策略的决策树 ```mermaid graph TD A[需要优化if-else?] --> B{分支数量} B -->|1-3个| C[提前return或字典映射] B -->|4-8个| D[策略模式或Switch表达式] B -->|8+个| E[状态模式或责任链] A --> F{是否处理状态变化?} F -->|是| G[状态模式] F -->|否| H{是否处理请求管道?} H -->|是| I[责任链模式] H -->|否| J[策略模式] ``` ## 最佳实践建议 1. **单一职责原则**:每个方法/类只负责一个功能 2. **开闭原则**:对扩展开放,对修改关闭(使用策略模式) 3. **圈复杂度监控**:使用工具如SonarQube监控代码复杂度[^3] 4. **渐进式重构**:不要试图一次性重构所有代码 5. **单元测试**:重构前确保有充分的测试覆盖率 > 当if-else分支超过5个时,策略模式通常是最佳选择;当处理对象状态变化时,状态模式更合适;对于简单的值映射,字典映射是最轻量的解决方案[^2][^4]。 通过应用这些模式和技术,可以显著提高代码的可读性、可维护性和可扩展性,同时降低圈复杂度[^1][^3]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值