C# 去除if-else以及子类管理 (上)策略模式+工厂模式

本文介绍如何利用策略模式和工厂模式实现游戏VIP系统的折扣计算。通过定义会员接口及其实现类,结合上下文环境和工厂模式,实现不同消费水平对应不同会员等级的折扣策略。

这是我的第一篇技术博客,虽说技术点不多,但是练习写下来也多多少少是个收获,这里我会根据我遇到的问题和我使用的解决方法一点一点进行代码更改。废话不多少直接进入正题。

一般在编码过程当中,我们需要通过一个条件进行筛选某一子类的时候,需要用到大量的if else或者Swich,本文章将在一点点的解决这些问题,在需要新的需求的时候,直接添加子类便可实现相关功能。

我们都知道,处理一个问题的时候,使用策略模式可以达到多样化的处理,并且可以在不修改原有Context的情况下进行实现。

举个例子,某游戏中的Vip机制,在一定金钱下的消费是普通会员,没有折扣。当消费到一定程度的时候,这里我们假设为1000金的时候,升级为初级会员,可以享受九折折扣,这里我们直接使用策略模式进行编写代码:

会员基类:IVipStrategy,根据当前消费price计算当前会员制度的折扣价格。

public interface IVipStrategy
{
    float GetExtenditure(float price);
}

消费等级的子类,大众会员PublicVipStrategy, 初级会员 JuniorVipStrategy。

public class PublicVipStrategy : IVipStrategy
{
    public float GetExtenditure(float price)
    {
        return price;
    }
}

public class JuniorVipStrategy : IVipStrategy
{
    public float GetExtenditure(float price)
    {
        return price * 0.9f;
    }
}

上下文环境我们使用消费者PlayerContext

using System;

public class Consumer
{
    private float _price;
    private float _totalConsume;
    private IVipStrategy _vipStrategy;

    public Consumer()
    {
        _vipStrategy = new PublicVipStrategy();
    }
    public void Buy(int price)
    {
        _price = GetConsume(price);
        Console.WriteLine("消费了 : " + _price);
        _totalConsume += _price;
    }
    private float GetConsume(int price)
    {
        if ((0 <= _totalConsume) && (_totalConsume < 1000))
            _vipStrategy = new PublicVipStrategy();
        else if ((1000 <= _totalConsume) && (_totalConsume < 2000))
            _vipStrategy = new JuniorVipStrategy();
        return _vipStrategy.GetExtenditure(price);
    }
}

然后我们在主函数中调用测试一下

public class ContextView
{
    public void Main()
    {
        Consumer consumer = new Consumer();
        consumer.Buy(1000);
        consumer.Buy(1000);
    }
}

输出结果:

  

这里我们就可以看到两次购买价值1000金的商品,第一次由于是大众会员不享受折扣优惠,则直接全价购买。购买完毕之后达到了下一等级Vip要求,然后第二次购买的时候则享受9折优惠。接下来我们加入工厂模式将Cosumer中的策略选择提取出来。

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)
    {
        float totalConsume = consumer.TotalConsume;
        if ((0 <= totalConsume) && (totalConsume < 1000))
            return new PublicVipStrategy();
        if ((1000 <= totalConsume) && (totalConsume < 2000))
            return new JuniorVipStrategy();
        return new PublicVipStrategy();
    }
}

改写下消费者类

using UnityEngine;

public class Consumer
{
    private float _price;
    public float TotalConsume { private set; get;  }//修改为属性
    private IVipStrategy _vipStrategy;

    public Consumer()
    {
        _vipStrategy = new PublicVipStrategy();
    }

    public void Buy(int price)
    {
        _price = GetConsume(price);
        Debug.Log("消费了 : " + _price);
        TotalConsume += _price;
    }

    private float GetConsume(int price)
    {
        //由工厂选择策略
        _vipStrategy = VipStrategyFactory.Instance.GetVipStrategy(this);
        return _vipStrategy.GetExtenditure(price);
    }
}

通过工厂我们可以看得到这里我们仍然需要使用到if else进行策略选择,当我们添加新的会员政策的时候,需要编写子类,同时需要修改工厂添加新的条件,在下一篇我们引入C#特性的概念给每一个会员添加自己的消费范围。

转载请标明出处。

<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、付费专栏及课程。

余额充值