在升级一些旧代码的同时,我发现这两个 OO 原则似乎相互冲突。

考虑以下伪代码(它是我遇到的简化版本):

int numberOfNewRecords;
int numberOfOldRecords;
int numberOfUndefinedRecords;

void ColourAndCount()
{
    foreach(Row row in dataGridView1.Rows)
    {
        switch(row.Cells["Status"])
        {
            case: "Old"
                row.BackColor = Color.Red;
                numberOfOldRecords++;
                break;
            case: "New"
                row.BackColor = Color.Blue;
                numberOfNewRecords++;
                break;
            default:
                row.BackColor = Color.White;
                numberOfUndefinedRecords++;
                break;
        }
    }
}

这段代码做了两件事:它按状态统计记录的数量,并且还为每一行着色,再次按它们的状态。这很困惑,但是由于这两个操作(到目前为止)总是同时被调用,所以它没有引起任何问题,并且使得像附加状态这样的维护需求很容易添加。

尽管如此,单一职责原则告诉我应该将其拆分为两个单独的方法:

(编辑)小注:我刚刚意识到我可能在这里误用了术语“单一职责原则”,据我所知,它指的是类。 “每个方法一个操作”设计模式的术语是什么?
int numberOfNewRecords;
int numberOfOldRecords;
int numberOfUndefinedRecords;

void Count()
{
    foreach(Row row in dataGridView1.Rows)
    {
        switch(row.Cells["Status"])
        {
            case: "Old"
                numberOfOldRecords++;
                break;
            case: "New"
                numberOfNewRecords++;
                break;
            default:
                numberOfUndefinedRecords++;
                break;
        }
    }
}

void Colour()
{
    foreach(Row row in dataGridView1.Rows)
    {
        switch(row.Cells["Status"])
        {
            case: "Old"
                row.BackColor = Color.Red;
                break;
            case: "New"
                row.BackColor = Color.Blue;
                break;
            default:
                row.BackColor = Color.White;
                break;
        }
    }
}

但这违反了不要重复自己:循环和 switch 语句在两种方法中都是重复的,并且由于此代码最可能的升级路径是添加其他状态,因此它使 future 的升级更加困难而不是更少。

我很难找到最优雅的重构方式,所以我觉得最好问问社区,以防我遗漏了一些明显的东西。你会如何解决这种情况?

(编辑)

我想出了一个可能的解决方案,但在我看来,它就像一个过度设计一个简单问题的例子(它并没有真正解决最初的单一职责问题)。
struct Status
{
    public string Name,
    public int Count,
    public Color Colour,
}

Dictionary<string, Status> StatiiDictionary = new Dictionary<string, int>();
void Initialise()
{
    StatiiDictionary.Add(new Status("New", 0, Color.Red));
    StatiiDictionary.Add(new Status("Old", 0, Color.Blue));
    StatiiDictionary.Add(new Status("Undefined", 0, Color.White));
}

void ColourAndCountAllRows()
{
    foreach(Row row in dataGridView1.Rows)
    {
        CountRow(row, StatiiDictionary);
        ColourRow(row, StatiiDictionary);
    }
}

void CountRow(Row row, Dictionary<string, Status> StatiiDictionary)
{
    StatiiDictionary[row.Cells["Status"]].Count++;
}

void ColourRow(Row row, Dictionary<string, Status> StatiiDictionary)
{
    row.BackColour = StatiiDictionary[row.Cells["Status"]].Colour;
}

最佳答案

出于实用的原因,需要不时违反许多编程规则。就您而言,我同意 DRY 和 SRP 似乎在竞争,因此我建议使用两个标准来决定获胜者:

  • 代码遵守每一个意味着什么。
  • 应用程序遵守每一项意味着什么。

  • 在这种情况下,两次枚举网格行的效率低下对我来说似乎是压倒一切的因素,在这种特殊情况下 DRY 会胜过 。在其他一些情况下,它可能是相反的。

    添加注释来解释您做出的决定以及原因是值得的,以便以后查看代码的任何人都清楚。这正是注释应该用于的事情,即 为什么 代码正在做它正在做的事情,而不仅仅是它正在做的事情。

    关于c# - 哪个优先 : Don't Repeat Yourself or the Single Responsibility Principle?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/23097222/

    10-09 14:31