重新分解包含两个参数的IF语句集合

时间:2013-10-25 08:13:52

标签: c# refactoring

目前我有七个if语句类似于以下代码:

if(hit.collider.gameObject.tag == "Colour1" && start_time > look_at_time)
{
    new_colour1.ChangeObjectMaterialColour(hit.collider.gameObject.renderer.material.color);

   var colums = GameObject.FindGameObjectsWithTag("column");
   foreach( GameObject c in colums)
    c.GetComponent<MeshRenderer>().materials[1].color = new_colour1.orignalMaterial;
}


else if(hit.collider.gameObject.tag == "Colour2" && start_time > look_at_time)
{
    new_colour2.ChangeObjectMaterialColour(hit.collider.gameObject.renderer.material.color);
    var colums = GameObject.FindGameObjectsWithTag("column");
    foreach( GameObject c in colums)
       c.GetComponent<MeshRenderer>().materials[1].color = new_colour2.orignalMaterial;
}

每个语句大约有6行代码,占用了大量空间,读起来有点棘手。我想要做的是找到一种方法来重新考虑这一点,这样我的代码就不那么笨重,也不会占用太多空间。

我曾考虑将if语句的集合更改为switch语句,但我发现switch语句不能像上面那样处理两个参数。如果有任何其他方式我可以重新考虑我的代码,但保持相同的功能或我坚持我的if语句集合?

修改

更新为包含我的7个语句中的两个。 请注意,我正在尝试减少我拥有的IF语句的数量,或者找到一种更聪明的方法来实现它们。我不想添加任何额外的代码行或if语句。

2 个答案:

答案 0 :(得分:2)

老实说,我认为在你的情况下最可读和可维护的只是将那些if块中的逻辑移动到函数中:

  if(hit.collider.gameObject.tag == "Colour1" && start_time > look_at_time)
    {
        DoTheThing(new_colour1);
    }
if(hit.collider.gameObject.tag == "Colour2" && start_time > look_at_time)
    {
        DoTheThing(new_colour2);
    }
//and so on



 void DoTheThing(MyType newColour)
  {
 newColour.ChangeObjectMaterialColour(hit.collider.gameObject.renderer.material.color);
      var colums = GameObject.FindGameObjectsWithTag("column");
       foreach( GameObject c in colums)
        c.GetComponent<MeshRenderer>().materials[1].color = newColour.orignalMaterial;
    }

关于使用switch,您当然可以这样做:

switch(hit.collider.gameObject.tag)
{
  case "Colour1":
      if (start_time>look_at_time)
      {
        //do something
      }
      else if (start_time<look_at_time)
      {
        //something else
      }
      else
      {
         //they are equal, etc, etc
      }
    break;
case "Colour2":
  //and so on
}

或者如果所有if块在start_timelook_at_time之间进行相同的比较,那么您可以将其反转:

enum TimeDifference
{
   LessThan,Equal,GreaterThan
}
//just one way to get a constant switchable value, not necessarily the best
var diff = TimeDifference.Equal;
if (start_time>look_at_time) {diff=TimeDifference.LessThan}
else if (start_time<look_at_time) {diff=TimeDifference.GreaterThan}

switch(diff)
{
  case TimeDifference.LessThan:
     switch(hit.collider.gameObject.tag)
     {
       case "Colour1":
         //do something for Colour1
        break;   
        case "Colour2":
         //do something for Colour2
        break;
      }//end switch Colour
     break;
  case TimeDifference.GreaterThan
    switch(hit.collider.gameObject.tag)
     {
       case "Colour1":
         //do something for Colour1
        break;   
        case "Colour2":
         //do something for Colour2
        break;
      }//end switch Colour
     break;  
   default:
    //nested switch for Colour in the == case, you get the idea.
}

尽管上述任何一个与几个格式良好且分离的if块的可读性是非常值得商榷的。

另一种方法是使用Dictionary<string,Action<int,int>> :(假设start_timelook_at_time都是int并且所有逻辑都以某种方式涉及它们。

var Actions = new Dictionary<string,Action<int,int>>();
Actions.Add("Colour1",(s,l)=>{
 if (start_time>look_at_time)
          {
            //do something
          }
          else if (start_time<look_at_time)
          {
            //something else
          }
          else
          {
             //they are equal, etc, etc
          }

});

然后您的主代码变为1行:

Actions[hit.collider.gameObject.tag](start_time,look_at_time);

我相信还有很多方法可以重新安排代码。

答案 1 :(得分:1)

感谢您更新代码,现在我们可以开始查看重复的内容了。例如,两个代码块之间的唯一区别是if语句中的字符串"Color1""Color2",以及new_colour1替换的变量new_colour2。 / p>

从这里我建议如下:

//This should be declared once - e.g. class level not method level.
var colorDict = new Dictionary<string, [new_color_type]> 
                    {{"Colour1", new_colour1}, {"Colour2", new_colour2}};

[new_color_type] newColor;
if(start_time > look_at_time && colorDict.TryGetValue(
        hit.collider.gameObject.tag,
        out newColor))
{
   newColor.ChangeObjectMaterialColour(
                            hit.collider.gameObject.renderer.material.color);

   var colums = GameObject.FindGameObjectsWithTag("column");
   foreach( GameObject c in colums)
      c.GetComponent<MeshRenderer>().materials[1].color =
                                                    newColor.orignalMaterial;
}