【问题标题】:Refactoring Similar Methods重构类似的方法
【发布时间】:2012-08-26 07:50:27
【问题描述】:

使用这种代码:

    public void UpdateCellFont(int id, string colName, Font font)
    {
        CellLocation location = new CellLocation(id, colName);

        if (CellAppearances.ContainsKey(location))
        {
            CellAppearances[location].Font = font;
        }
        else
        {
            CellAppearance cell = new CellAppearance(font, _DefaultBackColor, _DefaultForeColor);
            CellAppearances.Add(location, cell);
        }
    }

    public void UpdateCellBackColor(int id, string colName, Color backColor)
    {
        CellLocation location = new CellLocation(id, colName);

        if (CellAppearances.ContainsKey(location))
        {
            CellAppearances[location].BackColor = backColor;
        }
        else
        {
            CellAppearance cell = new CellAppearance(_DefaultFont, backColor, _DefaultForeColor);
            CellAppearances.Add(location, cell);
        }
    }

    public void UpdateCellForeColor(int id, string colName, Color foreColor)
    {
        CellLocation location = new CellLocation(id, colName);

        if (CellAppearances.ContainsKey(location))
        {
            CellAppearances[location].ForeColor = foreColor;
        }
        else
        {
            CellAppearance cell = new CellAppearance(_DefaultFont, _DefaultBackColor, foreColor);
            CellAppearances.Add(location, cell);
        }
    }

这些方法几乎都做同样的事情——每一个都会更新 Font、BackColor 或 ForeColor(或者如果字典中没有条目,它们会创建一个新条目。

当它们作用于强类型的 CellAppearance 时,如何减少此处的重复?

谢谢

【问题讨论】:

    标签: c# refactoring


    【解决方案1】:

    那么直截了当呢?

    public CellAppearance GetAppearance(int id, string colName){
        var location = new CellLocation(id, colName);
        if(!CellAppearances.ContainsKey(location))
           CellAppearances.Add(location, cell);
        return CellAppearances[location];
    }
    
    // usage:
    GetAppearance(1,"hello").Font = myFont;
    GetAppearance(2,"blubb").BackColor = myColor;
    

    【讨论】:

    • OK 所以“单元格”将使用默认值创建。然后我仍然有三种方法(UpdateFont、UpdateBackColor、UpdateForeColor),但这些应该只调用一行 GetAppearance(id,"colName").Font = font etc?
    • 是的......对......在您的解决方案中,您甚至可以先创建一个默认样式,然后只更新特定设置......恕我直言,这种方式既干净又简单......
    • F*** 我不知道如何接受你的改变...看起来不错——比我的更正确;)
    【解决方案2】:

    代表救援!

    在这种情况下,TheHe 的答案应该符合要求,但通常您可以通过使用委托作为方法参数来解决这种情况(并且组织您的主要方法有点不同):

    public void UpdateCellProperty (int id, string colName,
                                    Action<CellAppearance> appearanceAction)
    {
        CellAppearance cell;
    
        CellLocation location = new CellLocation(id, colName);
        if (CellAppearances.ContainsKey(location))
        {
            cell = CellAppearances[location];
        }
        else
        {
            cell = new CellAppearance(_DefaultFont, _DefaultBackColor,
                                      _DefaultForeColor);
        }
        appearanceAction(cell);
    }
    
    public void UpdateCellFont(int id, string colName, Font font)
    {
        UpdateCellProperty(id, colName, c => c.Font = font);
    }
    
    public void UpdateCellBackColor(int id, string colName, Color backColor)
    {
        UpdateCellProperty(id, colName, c => c.BackColor = backColor);
    }
    
    public void UpdateCellForeColor(int id, string colName, Color foreColor)
    {
        UpdateCellProperty(id, colName, c => c.ForeColor = foreColor);
    }
    

    我已经看到这种模式被称为“中间模式的洞”。非常合适:您定义了一个带有“孔”的方法体,该“孔”注入了委托。

    【讨论】:

    • @TheHe 你的意思是-1? :) 都一样。你是对的,它不像你的解决方案那样简洁,但我想指出“重构类似方法”的通用模式。它在很多场合都对我很有帮助。它将重复部分与可变代码隔离开来。核心方法往往非常稳定,并且在委托中可以专注于任务本身,而无需仪式性代码。
    【解决方案3】:

    正是这些方法的条件性使它们变得复杂且具有重复性。如果 Appearance 已经存在,你做一件事;如果没有,你做别的事情。所以确保外观存在:

    public void EnsureCellAppearance(CellLocation location)
    {
        if (CellAppearances.ContainsKey(location))
            return;
        CellAppearances.Add(location, new CellAppearance(_DefaultFont, _DefaultBackColor, _DefaultForeColor));
    }
    

    现在你的方法更简单了:

    public void UpdateCellFont(int id, string colName, Font font)
    {
        CellLocation location = new CellLocation(id, colName);
        EnsureCellAppearance(location);
        CellAppearances[location].Font = font;
    }
    

    【讨论】:

    • 是的,这是其中的一部分——但请注意,需要更新的是 Font、BackColor 和 ForeColor(实际上还有更多,但为了清楚起见我将其删减了)。所以我仍然需要三种方法 - UpdateCellFont、UpdateForeColor、UpdateBackColor...
    【解决方案4】:

    您可能必须使用反射将代码泛化到不同类型的多个字段。不确定是否值得。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-01-13
      • 1970-01-01
      • 2021-07-16
      • 2020-03-29
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多