目前国内还是很缺AI人才的,希望更多人能真正加入到AI行业,共同促进行业进步,增强我国的AI竞争力。想要系统学习AI知识的朋友可以看看我精心打磨的教程 http://blog.csdn.net/jiangjunshow,教程通俗易懂,高中生都能看懂,还有各种段子风趣幽默,从深度学习基础原理到各领域实战应用都有讲解,我22年的AI积累全在里面了。注意,教程仅限真正想入门AI的朋友,否则看看零散的博文就够了。

前言

兄弟,咱说实话,你是不是也干过这种事儿?

打开编辑器,手速起飞,if (status == 1) 接着就是一大坨逻辑,else if (status == 2) 再来一坨… 等你写到第8个else if的时候,屏幕都快不够长了,右边的滚动条细得像根头发丝。这时候产品经理探头过来说:“再加个新状态哈”,你当时的心态估计跟那团乱麻的耳机线差不多——剪不断理还乱。

别慌,今天咱不整那些虚头巴脑的理论,就聊点实在的。我给你准备了5个设计模式,不是让你背定义应付面试的,是真正能把你代码里那些俄罗斯套娃一样的if-else给拆了,换成清晰优雅的写法。看完你要是觉得没用,评论区随便喷我。


一、策略模式:别把武功秘籍塞在一个抽屉里

1.1 先看看你现在的代码

假设你在做一个电商系统的支付模块,用户可能用支付宝、微信、银行卡支付。新手写法可能是这样的:

public void ProcessPayment(string paymentType, decimal amount)
{
    if (paymentType == "Alipay")
    {
        // 50行支付宝API调用逻辑
        Console.WriteLine("支付宝支付{amount}元,调网关、验签、回调处理...");
    }
    else if (paymentType == "WeChat")
    {
        // 又是50行微信API逻辑,长得还差不多但细节不同
        Console.WriteLine("微信支付{amount}元,调统一下单、查订单状态...");
    }
    else if (paymentType == "BankCard")
    {
        // 再来50行银联接口
        Console.WriteLine($"银行卡支付{amount}元,走银联通道...");
    }
    // 明天加个Apple Pay?后天加个数字人民币?继续else if?
}

这代码看着熟不熟?就像你把羽绒服、短袖、西装全塞在一个抽屉里,找件衣服得翻半天。而且每次加新支付方式,你都得改这个类——违反开闭原则不说,万一改崩了,整个支付流程都完蛋。

1.2 策略模式重构:分类挂衣钩

说白了,策略模式就是"专业的事交给专业的类"。咱定义一个支付策略接口,每种支付方式自己实现一套:

// 定义策略接口
public interface IPaymentStrategy
{
    void Pay(decimal amount);
    bool Supports(string paymentType);
}

// 支付宝策略
public class AlipayStrategy : IPaymentStrategy
{
    public bool Supports(string paymentType) => paymentType == "Alipay";

    public void Pay(decimal amount)
    {
        // 支付宝专属逻辑,独立维护
        Console.WriteLine($"[支付宝] 调用开放平台SDK,金额:{amount:C}");
        // 验签、回调、对账...各玩各的
    }
}

// 微信策略
public class WeChatPayStrategy : IPaymentStrategy
{
    public bool Supports(string paymentType) => paymentType == "WeChat";

    public void Pay(decimal amount)
    {
        Console.WriteLine($"[微信支付] 调用统一下单API,金额:{amount:C}");
    }
}

// 银行卡策略
public class BankCardStrategy : IPaymentStrategy
{
    public bool Supports(string paymentType) => paymentType == "BankCard";

    public void Pay(decimal amount)
    {
        Console.WriteLine($"[银联] 对接银联云闪付,金额:{amount:C}");
    }
}

然后支付服务这样写,用到.NET 9的依赖注入和主构造函数(C# 12特性),代码清爽得像刚整理的衣柜:

public class PaymentService(IPaymentStrategy[] strategies)
{
    public void ExecutePayment(string type, decimal amount)
    {
        // 用C# 9的模式匹配找对应策略,比if-else链优雅多了
        var strategy = strategies.FirstOrDefault(s => s.Supports(type))
            ?? throw new ArgumentException($"不支持的支付方式:{type}");

        strategy.Pay(amount);
    }
}

// 注册时.NET 9的DI容器会自动发现所有策略
builder.Services.AddScoped<IPaymentStrategy, AlipayStrategy>();
builder.Services.AddScoped<IPaymentStrategy, WeChatPayStrategy>();
builder.Services.AddScoped<IPaymentStrategy, BankCardStrategy>();

现在加Apple Pay?新建个类实现接口,注册到DI容器,其他代码完全不用动。这就叫"对扩展开放,对修改封闭",听着高大上,其实就是别把鸡蛋放一个篮子里。


二、工厂模式:别让new关键字污染你的业务代码

2.1 创建对象也是重灾区

有时候if-else不是出现在业务逻辑,而是出现在new对象的时候。比如你要根据用户等级创建不同的会员实例:

public Member CreateMember(string level)
{
    if (level == "Gold")
        return new GoldMember { Discount = 0.8m, PointsMultiplier = 2 };
    else if (level == "Silver")
        return new SilverMember { Discount = 0.9m, PointsMultiplier = 1.5 };
    else if (level == "Bronze")
        return new BronzeMember { Discount = 0.95m, PointsMultiplier = 1 };
    else
        return new RegularMember { Discount = 1.0m, PointsMultiplier = 1 };
}

这种代码的问题在于,创建逻辑和业务逻辑搅在一起,而且每次改会员权益,你都得来这里改魔法数字。工厂模式就是专门解决"造东西"这件事的。

2.2 工厂模式:开个专门的生产车间

咱用.NET 9的KeyedService特性(这是2024年底的新功能,正好符合2025-2026的技术时效性),配合工厂模式:

// 会员基类
public abstract class Member
{
    public abstract string LevelName { get; }
    public abstract decimal Discount { get; }
    public abstract int PointsMultiplier { get; }
}

public class GoldMember : Member
{
    public override string LevelName => "金牌会员";
    public override decimal Discount => 0.8m;
    public override int PointsMultiplier => 2;
}

// Silver、Bronze类似,省略...

// 工厂接口
public interface IMemberFactory
{
    Member Create(string level);
}

// 2025年的写法:用字典+委托,配合C# 12的集合表达式
public class MemberFactory : IMemberFactory
{
    private readonly Dictionary<string, Func<Member>> _factories = new()
    {
        ["Gold"] = () => new GoldMember(),
        ["Silver"] = () => new SilverMember(),
        ["Bronze"] = () => new BronzeMember(),
        ["Regular"] = () => new RegularMember()
    };

    public Member Create(string level)
    {
        // 用C# 8的可空引用类型+模式匹配,一行搞定
        return _factories.TryGetValue(level, out var factory) 
            ? factory() 
            : throw new ArgumentException($"未知会员等级:{level}");
    }
}

在.NET 9的Minimal API里用得更爽:

app.MapPost("/members", (string level, IMemberFactory factory) =>
{
    var member = factory.Create(level);
    return Results.Ok(new { member.LevelName, member.Discount });
});

你看,创建逻辑彻底从业务代码里抽出来了,就像麦当劳的后厨,前台(业务代码)只管点单,汉堡怎么煎(对象怎么创建)是后厨(工厂)的事。


三、状态模式:电梯按钮别用if-else判断

3.1 状态判断是if-else的重灾区

假设你在开发一个订单系统,订单有"待付款"、“已付款”、“已发货”、“已完成”、"已取消"这几个状态。每个操作都要判断当前状态:

public void ShipOrder(Order order)
{
    if (order.Status == "Paid")
    {
        // 可以发货
        order.Status = "Shipped";
        // 50行发货逻辑
    }
    else if (order.Status == "Pending")
    {
        throw new InvalidOperationException("还没付款发什么货?");
    }
    else if (order.Status == "Shipped")
    {
        throw new InvalidOperationException("都发过了,别重复操作");
    }
    // else if 还能写10行...
}

public void CancelOrder(Order order)
{
    if (order.Status == "Pending" || order.Status == "Paid")
    {
        // 可以取消
    }
    else if (order.Status == "Shipped")
    {
        throw new InvalidOperationException("货都发了,取消个锤子");
    }
    // 又是无尽的else if...
}

这代码就像电梯里的按钮,每个楼层都要if判断一下能不能停。状态多了之后,这些判断条件会散落在各个方法里,改个状态规则得全局搜索,漏改一个地方就是线上事故。

3.2 状态模式:把状态变成对象

状态模式的核心思想是"状态决定行为"。每个状态是一个类,自己决定能做什么操作:

// 订单上下文
public class Order
{
    public IOrderState State { get; set; } = new PendingState();
    public string CurrentStatus => State.GetType().Name.Replace("State", "");

    public void Pay() => State.Pay(this);
    public void Ship() => State.Ship(this);
    public void Cancel() => State.Cancel(this);
}

// 状态接口
public interface IOrderState
{
    void Pay(Order order);
    void Ship(Order order);
    void Cancel(Order order);
}

// 待付款状态
public class PendingState : IOrderState
{
    public void Pay(Order order)
    {
        Console.WriteLine("付款成功,切换到已付款状态");
        order.State = new PaidState();
    }

    public void Ship(Order order) => 
        throw new InvalidOperationException("还没付款,发不了货");

    public void Cancel(Order order)
    {
        Console.WriteLine("订单已取消");
        order.State = new CancelledState();
    }
}

// 已付款状态
public class PaidState : IOrderState
{
    public void Pay(Order order) =>
        throw new InvalidOperationException("已经付过款了");

    public void Ship(Order order)
    {
        Console.WriteLine("发货成功,切换已发货状态");
        order.State = new ShippedState();
    }

    public void Cancel(Order order)
    {
        Console.WriteLine("申请退款,取消订单");
        order.State = new CancelledState();
    }
}

// 已发货、已完成等状态类似实现...

现在业务代码清爽得一批:

var order = new Order();
order.Pay();      // 成功
order.Ship();     // 成功
// order.Cancel(); // 运行时自动抛异常:货都发了不能取消

这就好比电梯自己知道"我在10楼,按1楼就下行,按20楼就上行",不用外面的人if判断。所有状态规则集中在各自的状态类里,想改"已付款能不能取消"这种规则?只改PaidState一个类就行,不会影响到其他状态的逻辑。


四、责任链模式:报销审批别写死判断

4.1 多级审批的if-else噩梦

公司报销流程:小于1000主管批,1000-5000经理批,5000以上总监批。常规写法:

public void Approve(ExpenseRequest request, Employee employee)
{
    if (request.Amount < 1000)
    {
        if (employee.Title == "主管" || employee.Title == "经理" || employee.Title == "总监")
            Console.WriteLine("主管审批通过");
        else
            throw new Exception("权限不足");
    }
    else if (request.Amount < 5000)
    {
        if (employee.Title == "经理" || employee.Title == "总监")
            Console.WriteLine("经理审批通过");
        else
            throw new Exception("权限不足,找经理批");
    }
    else
    {
        if (employee.Title == "总监")
            Console.WriteLine("总监审批通过");
        else
            throw new Exception("权限不足,找总监批");
    }
}

这代码读起来像绕口令,而且规则一改(比如加个副总监级别),全得重写。

4.2 责任链:像击鼓传花一样传递请求

责任链模式把每个审批人看成链上的一个节点,自己能处理就处理,不能处理就传给下一个。用C# 12的required成员和.NET 9的record特性(虽然record主要是不可变,但这里用类更灵活):

// 审批请求
public record ExpenseRequest(string Description, decimal Amount);

// 抽象处理者
public abstract class ExpenseHandler
{
    protected ExpenseHandler? Next { get; private set; }

    public ExpenseHandler SetNext(ExpenseHandler next)
    {
        Next = next;
        return next; // 链式调用, fluent API风格
    }

    public virtual void Handle(ExpenseRequest request)
    {
        // 自己处理不了就扔给下一个,像击鼓传花
        Next?.Handle(request);
    }
}

// 主管处理者
public class SupervisorHandler : ExpenseHandler
{
    public override void Handle(ExpenseRequest request)
    {
        if (request.Amount < 1000)
        {
            Console.WriteLine($"主管审批通过:{request.Description},金额{request.Amount:C}");
        }
        else
        {
            Console.WriteLine("主管权限不够,提交给经理...");
            base.Handle(request);
        }
    }
}

// 经理处理者
public class ManagerHandler : ExpenseHandler
{
    public override void Handle(ExpenseRequest request)
    {
        if (request.Amount >= 1000 && request.Amount < 5000)
        {
            Console.WriteLine($"经理审批通过:{request.Description}");
        }
        else
        {
            Console.WriteLine("经理权限不够,提交给总监...");
            base.Handle(request);
        }
    }
}

// 总监处理者
public class DirectorHandler : ExpenseHandler
{
    public override void Handle(ExpenseRequest request)
    {
        if (request.Amount >= 5000)
        {
            Console.WriteLine($"总监审批通过:{request.Description},大额支出已备案");
        }
        else
        {
            throw new InvalidOperationException("金额异常,无法处理");
        }
    }
}

用起来像这样,跟搭积木似的:

// 组装责任链,顺序随意调
var supervisor = new SupervisorHandler();
var manager = new ManagerHandler();
var director = new DirectorHandler();

supervisor.SetNext(manager).SetNext(director);

// 发起审批,不用关心具体谁批
supervisor.Handle(new ExpenseRequest("买键盘", 800m));    // 主管批
supervisor.Handle(new ExpenseRequest("团建聚餐", 3000m)); // 经理批
supervisor.Handle(new ExpenseRequest("买服务器", 20000m));  // 总监批

这就像在公司里递报销单,主管看了觉得金额太大,直接传给经理,经理觉得还是大,再传给总监。你作为申请人,不用if判断该找谁,只需要把单子递出去,流程自己流转。以后加个"副总监"级别?插进链表里就行,其他处理者完全不用改。


五、字典+委托:把switch语句换成查字典

5.1 有时候你就是想简单点

上面那些模式都很好,但有时候你就是想干掉一个简单的switch或者短if-else链,没必要搞那么多类。这时候C#的Dictionary<string, Func<>>就是你的神器。

比如你要做个简单的命令行工具,根据输入命令执行不同操作:

// 传统写法
public void ExecuteCommand(string command)
{
    switch (command.ToLower())
    {
        case "start":
            StartService();
            break;
        case "stop":
            StopService();
            break;
        case "restart":
            RestartService();
            break;
        case "status":
            CheckStatus();
            break;
        default:
            Console.WriteLine("未知命令");
            break;
    }
}

5.2 现代C#写法:用字典做路由表

C# 12的集合表达式+.NET 9的Lambda优化,让这代码短得离谱:

public class CommandExecutor
{
    private readonly Dictionary<string, Action> _commandMap;

    public CommandExecutor()
    {
        // C# 12集合表达式,比传统写法简洁
        _commandMap = new()
        {
            ["start"] = () => Console.WriteLine("✅ 服务启动,端口8080"),
            ["stop"] = () => Console.WriteLine("🛑 服务停止,释放资源"),
            ["restart"] = () => 
            {
                Console.WriteLine("🔄 正在重启...");
                Task.Delay(1000).Wait();
                Console.WriteLine("✅ 重启完成");
            },
            ["status"] = () => Console.WriteLine("ℹ️ 运行中,内存占用256MB"),
            ["help"] = ShowHelp // 也可以引用现有方法
        };
    }

    public void Execute(string command)
    {
        // 一行替代整个switch,用C# 8的Null合并简化错误处理
        (_commandMap.GetValueOrDefault(command.ToLower()) 
            ?? (() => Console.WriteLine($"❌ 未知命令:{command},输入help查看支持命令")))();
    }

    private void ShowHelp() => 
        Console.WriteLine($"支持命令:{string.Join(", ", _commandMap.Keys)}");
}

这就像是把命令和处理方法做成了一本字典,查哪个词直接翻到那一页,O(1)复杂度,比switch的顺序匹配还快。而且动态扩展超简单——运行时都能往字典里加新命令,switch语句可做不到这点。

更骚的操作是结合.NET 9的ReadOnlySpan做高性能字符串key匹配(如果你在做高性能中间件),不过那是进阶玩法,这里先不展开。


写在最后:设计模式不是银弹,是工具箱

看完这5种写法,你是不是觉得手里的if-else突然不香了?但咱得说句公道话——设计模式不是让你把所有if-else都干掉的。

什么时候该用模式?

  • 条件分支超过3个,而且可能继续增加
  • 同样的判断逻辑在多个地方重复出现
  • 条件判断里混杂着不同层面的逻辑(比如既判断状态又执行业务)

什么时候保留if-else?

  • 简单的二分判断(比如if (user == null))
  • 性能极度敏感的场景(模式有多态开销)
  • 一次性脚本或者临时工具,怎么快怎么来

说白了,设计模式就像你工具箱里的扳手、螺丝刀、电钻,干活前先想想用哪个顺手,别拿电钻钉钉子,也别拿扳手拧螺丝——虽然都能凑合,但专业的事交给专业的工具,代码才能优雅又易维护。

下次写代码时,瞅见那个开始变长的if-else链,停三秒,想想今天聊的这5招。重构后的代码不仅你看着爽,接手的同事也会在心里默默给你点个赞(虽然嘴上可能不说)。

行,今天就聊到这儿,去试试吧!

目前国内还是很缺AI人才的,希望更多人能真正加入到AI行业,共同促进行业进步,增强我国的AI竞争力。想要系统学习AI知识的朋友可以看看我精心打磨的教程 http://blog.csdn.net/jiangjunshow,教程通俗易懂,高中生都能看懂,还有各种段子风趣幽默,从深度学习基础原理到各领域实战应用都有讲解,我22年的AI积累全在里面了。注意,教程仅限真正想入门AI的朋友,否则看看零散的博文就够了。

在这里插入图片描述

更多推荐