【读书活动感悟分享】愚公-《重构:改善既有代码的设计》感悟:改代码而不改变软件的外在表现_文章

【读书活动感悟分享】愚公-《重构:改善既有代码的设计》感悟:改代码而不改变软件的外在表现

常付亮
发表于 2025-11-11 11:57:04

最近通过公司举办的读书活动,有幸拜读了《重构》一书,这本书不愧是软件开发领域的经典之作,它深入探讨了如何通过重构技术提升代码的质量,提高代码的可维护性和可扩展性。书中开篇就强调重构是在不改变软件外部行为的前提下对软件内部结构进行调整,这个理念颠覆了重写要优于修改的思维。


其实,重构是一个开发人员的基本工作内容,是在每天的开发过程中都要用到的。离开了重构和测试,代码质量是难有保障的。举个最简单的例子,当你发现一个类中有几处用到了相同的代码,你把这几行代码提取到了一个私有函数中以供复用,这就是一次重构。


代码是一种平衡的产物,很多地方都在保持着某种平衡,有功能与性能的平衡,有可靠性与可维护性的平衡等等,每一次动手,都要有一个目标,是想改进局部代码,还是想改进类结构,只有针对不同的目的才能实施不同的方法。改动前,最好能有个预估,对可能产生的影响做到心中有数,以免引起不必要的后果。在“坏味道”的代码中是很有可能牵一发而动全身的,要注意安全。如果只是对类的私有成员的改动,那通常影响的范围有限,如果涉及到对公有成员或保护成员的改动,那就要注意了,简单的评估方式是充分利用IDE的搜索、引用等功能,把引用过此成员的代码行全部找出来,看看影响的范围有多广,如果有些代码不在你的控制之内,那就要慎重考虑这个重构了。每次改动尽量小,这样可以把影响限制到小范围。就像一个公式一样,如果同时改变其中的几个变量,那很难说是哪一个影响了结果,但如果一次只改变其中的一个,就可以确认其对结果的影响。尤其是当代码已经完成了用户需求,这时的重构只是为了让代码更好,切忌不要影响到已经得到用户确认的外在表现。无论你的开发是否是测试驱动,在重构时测试是保证代码正确的必要手段。修改-编译-测试,重复这个过程,直到达到目的。当你花了几分钟或者几个礼拜,已经让代码大为清爽的时候,回过头来对比曾经的“坏味道”,我想,你会喜欢上代码的,重构会发生在你写下一行代码的时刻,变成了编码能力了。少一行代码,就少一分出错的可能,别心疼你删除掉的代码,虽然那是你的心血,但那已经是历史,在重构代码中蜕变已经完成。


以下分享一个重构代码段示例,展示了如何通过重构手法优化代码结构:

using System;
using System.Collections.Generic;
using System.Linq;

// 重构前:包含过长函数和重复代码的类
public class OrderProcessorOld
{
    public void ProcessOrder(Order order)
    {
        // 验证订单
        if (order == null)
            throw new ArgumentException("订单不能为空");
        if (order.Items == null || !order.Items.Any())
            throw new ArgumentException("订单项目不能为空");
        if (order.Customer == null)
            throw new ArgumentException("客户信息不能为空");
        
        // 计算总价
        double total = 0;
        foreach (var item in order.Items)
        {
            total += item.Price * item.Quantity;
        }
        
        // 应用折扣
        if (order.Customer.IsVIP)
            total *= 0.9;
        else if (total > 1000)
            total *= 0.95;
            
        // 更新订单
        order.TotalAmount = total;
        order.Status = "PROCESSED";
        
        // 记录日志
        Console.WriteLine($"订单处理完成:订单ID={order.Id}, 总金额={total}, 状态={order.Status}");
    }
}

// 重构后:通过提取方法优化代码结构
public class OrderProcessor
{
    public void ProcessOrder(Order order)
    {
        ValidateOrder(order);
        double total = CalculateTotalAmount(order);
        total = ApplyDiscount(order, total);
        UpdateOrderStatus(order, total);
        LogOrderProcessing(order);
    }
    
    private void ValidateOrder(Order order)
    {
        if (order == null)
            throw new ArgumentException("订单不能为空");
        if (order.Items == null || !order.Items.Any())
            throw new ArgumentException("订单项目不能为空");
        if (order.Customer == null)
            throw new ArgumentException("客户信息不能为空");
    }
    
    private double CalculateTotalAmount(Order order)
    {
        return order.Items.Sum(item => item.Price * item.Quantity);
    }
    
    private double ApplyDiscount(Order order, double total)
    {
        if (order.Customer.IsVIP)
            return total * 0.9;
        else if (total > 1000)
            return total * 0.95;
        return total;
    }
    
    private void UpdateOrderStatus(Order order, double total)
    {
        order.TotalAmount = total;
        order.Status = "PROCESSED";
    }
    
    private void LogOrderProcessing(Order order)
    {
        Console.WriteLine($"订单处理完成:订单ID={order.Id}, 总金额={order.TotalAmount}, 状态={order.Status}");
    }
}

// 辅助类
public class Order
{
    public string Id { get; set; }
    public List Items { get; set; }
    public Customer Customer { get; set; }
    public double TotalAmount { get; set; }
    public string Status { get; set; }
}

public class OrderItem
{
    public double Price { get; set; }
    public int Quantity { get; set; }
}

public class Customer
{
    public bool IsVIP { get; set; }
}

// 示例使用
class Program
{
    static void Main()
    {
        var order = new Order
        {
            Id = "123",
            Items = new List
            {
                new OrderItem { Price = 100, Quantity = 2 },
                new OrderItem { Price = 200, Quantity = 1 }
            },
            Customer = new Customer { IsVIP = true }
        };
        
        var processor = new OrderProcessor();
        processor.ProcessOrder(order);
    }
}

这个重构示例展示了几个关键的重构手法:通过提取方法将长函数分解为多个单一职责的小函数,使用LINQ简化集合操作提升代码可读性,保持函数层次清晰便于单元测试和维护,且每个方法都有明确的命名,良好的命名是代码可读性和可维护性的关键。

95 0

评论


意见反馈