【读书活动实用案例分享】-愚公-《重构:改善既有代码的设计》实用案例_文章

【读书活动实用案例分享】-愚公-《重构:改善既有代码的设计》实用案例

戴枝衡
发表于 2025-11-11 20:49:41

《重构》一书中,着重强调代码的逻辑和结构,最好的办法就是用清晰的代码结构来管理复杂的代码,这对于我们日常工作中对数据库的操作同样重要,下面是我在长春城投数据同步工具中的一个代码改进的案例,改进后的代码结构更加清晰。

最初的数据同步工具是直接将查询不同数据库的操作写在确认按钮的点击事件里,如下所示:

public partial class SaaSForm: Form
{
    private const string BaseConnectionString = "Host=XXXX;Port=15432;Database=teldaccount;User Id=XXXX;Password=XXXXX;";
    private SqlConnection _connection;
    public SaaSForm()
    {
        InitializeComponent();
        _connection = new SqlConnection(BaseConnectionString );
    }

    private void BtnOK_Click(object sender, EventArgs e)
    {
        string sql = "select bc.* from  base_cashbalance bc WITH (INDEX(IX_cashbalance_MIX), NOLOCK) 
                            where 1=1 and bc.type ='2'";
        using (var command = new SqlCommand(sql, BaseConnectionString ))
        {
            var adapter = new SqlDataAdapter(command);
            var dataTable = new DataTable();
            adapter.Fill(dataTable);
            dataGridViewUsers.DataSource = dataTable; 
        }
    //和上面一样的,按钮中有对应的SQL连接串和执行逻辑等等不在重复写了
    }

但是这么写有多个问题:首先SQL的查询(或者插入/删除)逻辑辉散落在不同的按钮里面;其次,对于源库(特来电数据库)如teldaccount里面不止是查询1个表,可能是多个例如base_cashbalance/asc_cashbalancedetails等等,如果teldaccount数据库的连接串发生改变的话,涉及到的表查询对应按钮中的代码都需要修改;最后一个问题就是页面复杂且混乱,不好用。

解决方法:使用仓储模式,核心思想是将数据库访问逻辑全都写在一个独立的类里面,然后调用的地方通过这个类提供的接口来存取数据,也就是说,使用的地方没有关注这个方法是咋实现的。


public class TeldAscCashBalanceRepository : Repository
{
    public override string IDColumnName => "ID";
    public override string DBName => "teldaccount";

    public int GetTeldAscCashBalanceCount(string cashBalanceID, DateTime? start, DateTime? end)
    {
        int result = 0;
        string sql = @$" select count(1) as Count from ASC_CashBalanceDetails as ac with(nolock) 
                     where CashAccountBookID='{cashBalanceID}'  and lastmodifytime >= '{start}'
                    and LastModifyTime < '{end}' ";

        var ds = this.DB.ExecuteDataSet(sql);
        if (ds.Tables.Count > 0)
        {
            var dt = ds.Tables[0];
            if (dt == null || dt.Rows == null || dt.Rows.Count == 0) return 0;
            foreach (DataRow dr in dt.Rows)
            {
                result = Convert.ToInt32(dr["Count"]);
            }
        }
        return result;
    }

    public List GetTeldAscCashBalanceList(string cashBalanceID, int offset, DateTime? start, DateTime? end)
    {
        string sql = $@" select ac.* from ASC_CashBalanceDetails as ac with(nolock)
                        where CashAccountBookID='{cashBalanceID}' 
                        and lastmodifytime >= '{start}' and LastModifyTime < '{end}' 
                        order by ac.id offset {offset} row fetch next 100 rows only ";
        return GetTObjectsBySql(sql);
    }

很明显代码的逻辑更清晰了,但是不能说上面的代码没有用,那也是思考问题的过程,优秀的代码可能不是一步到位写出来的,都是边写边优化,让代码的质量越来越高。

关于下一步的改进点:在上面的方法中,是直接把参数给拼里面的,没有参数化,我在最开始是参数化的,但是发现查询超时,目前我还没确定超时是不是和参数化有关系,后面会继续研究清楚。

94 0

评论


意见反馈