Рефакторинг коллекции операторов IF, содержащих два аргумента
На данный момент у меня есть семь операторов 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 ответа
Спасибо за обновление вашего кода, теперь мы можем начать смотреть на то, что дублируется. Например, единственное различие между двумя блоками кода - строка "Color1"
а также "Color2"
в операторе if и переменной new_colour1
который заменен на new_colour2
,
Отсюда я бы предложил что-то вроде следующего:
//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;
}
Честно говоря, я считаю, что наиболее удобочитаемым и понятным в вашем случае является просто переместить логику блоков 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_time
а также look_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_time
а также look_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);
И я уверен, что есть еще много способов изменить этот код.