在 C# 中清理超大箭头反模式
cleaning up super gross arrow head anti-pattern in c#
我对编码还很陌生,我希望尽早改掉坏习惯并开始编写干净高效的代码。我正在开发一个引用 API 的控制台应用程序,并且我有一系列深度嵌套的“if”(最高可达 10 层!)。
commonLogic forQuote = new commonLogic();
if (countryRes == CountryDes)
{
//staying in country
try2:
//display reasons for travel
Console.WriteLine("What Best Describes Your Reason For Traveling?");
Console.WriteLine(" ");
Console.WriteLine("1. United States Resident traveling Inside the U.S.");
Console.WriteLine("2. Visiting United States For Business or Pleasure.");
Console.WriteLine("3. Immigrating to The Unites States.");
Console.WriteLine("4. Student, Faculty Member or Scholar With a J-1, F-1, H-3, M-1, or Q-1 Visa.");
Console.WriteLine(" ");
var x = Console.ReadLine();
Console.Clear();
if (x == "1")
{
//US resident
//first print
forQuote.gatherUserData();
}
else if (x == "2")
{
try3:
//visiting the US
Console.WriteLine("What Type of Coverage Do You Need?");
Console.WriteLine(" ");
Console.WriteLine("1. Medical voerage");
Console.WriteLine("2. Trip Cancellation");
var r = Console.ReadLine();
Console.WriteLine(" ");
Console.Clear();
if (r == "1")
{
//medical coverage
Console.WriteLine("What Type of Medical Coverage Do You Want?");
Console.WriteLine(" ");
Console.WriteLine("1. Scheduled benifits");
Console.WriteLine("2. Comprehensive Benifits");
var s = Console.ReadLine();
Console.WriteLine(" ");
Console.Clear();
if (s == "1")
{
//second print
forQuote.gatherUserData();
}
else if (s == "2")
{
//comprehensive benifits
//third print
forQuote.gatherUserData();
}
else
{
//first else
Console.WriteLine("Invalid Input. Please Try Again");
}
}
else if (r == "2")
{
//trip canccelation
//fourth print
forQuote.gatherUserData();
}
else
{
//secondelse
Console.WriteLine("Invalid Input. Please Try Again");
goto try3;
}
}
else if (x == "3")
{
//immigration
//fithprint
forQuote.gatherUserData();
}
else if (x == "4")
{
//students...
//sixthprint
forQuote.gatherUserData();
}
else
{
//thirdelse
Console.WriteLine("Invalid Input. Please try Again");
goto try2;
}
}
这只是 if
总巢穴中的一小部分样本。我做了很多关于清理这个问题的研究,但我很难understanding/using找到我找到的答案。
我在重构时遇到的最大问题是 if
之后的每个都直接依赖于它之前的 if
。
我还对您需要达到每个 if
的输入进行了逻辑分析 table。如果有帮助,我会把它放在这里:
Excel table showing if paths
非常感谢您的帮助,并且解释为什么您的回答提高了可读性和效率也将是极好的。
看这段代码:
bool loop = true;
while(loop)
{
Console.WriteLine("Question");
Console.WriteLine("1. Ans1");
Console.WriteLine("2. Ans2");
Console.WriteLine("3. Exit");
string resp = Console.ReadLine();
switch(resp)
{
case "1":
Console.WriteLine("Ans1 chosen");
break;
case "2":
SomeQuestion();
break;
case "3":
loop = false;
break;
default:
Console.WriteLine("Invalid Input. Please try Again");
break;
}
}
void SomeQuestion()
{
bool loop = true;
while(loop)
{
Console.WriteLine("Question secon level");
Console.WriteLine("1. Ans3");
Console.WriteLine("2. Ans4");
Console.WriteLine("3. Exit");
string resp = Console.ReadLine();
switch(resp)
{
case "1":
Console.WriteLine("Ans1 chosen");
break;
case "2":
break;
case "3":
loop = false;
break;
default:
Console.WriteLine("Invalid Input. Please try Again");
break;
}
}
}
这道题很简单,一道题就说明了思路。
- 而是转到有条件的循环。
- 相反,如果一个开关使代码更具可读性。
我们先分解一些眼前的问题。
goto 语句(错误):
此语句令人困惑,因为它不符合执行流程。它基本上说 "Go to this arbitrary point in code that you have to find"。现在将其乘以 3 或 4,您将得到一个带有许多传送点的迷宫。你会很快迷路。
以下是如何解决此问题的示例:
if(condition)
{
try2:
// do stuff
if(condition2)
{
// Do more stuff
}
else
{
// Report error
goto try2;
}
}
// Replace with:
while(condition)
{
// do stuff
if(condition2)
{
// Do more stuff
break;
}
else
{
// Report error
continue; // Goes to the top of the loop
}
}
这个例子并不完美,从技术上讲你不需要 "continue",但我想解释一下它的用法。
命名约定:
每个class名称、变量名称、方法名称等都需要一个描述性标识符。 "loop" 什么也没告诉我。命名尽可能具有描述性。如果这样做之后仍然存在一些歧义,在定义中使用注释来清除它。
嵌套循环:
好的,这就是你程序的整体设计。不幸的是,询问一堆相关问题的控制台应用程序将会变得混乱。
为什么?
因为 WPF 等用户界面框架可以更好地处理此类逻辑。例如,您的很多逻辑都可以在按钮处理程序和控件属性中处理。
但是,您仍然可以改进您的代码。但是,它需要非常面向对象的设计。我会选择 状态模式 作为开始。
状态模式资源:http://www.dotnettricks.com/learn/designpatterns/state-design-pattern-c-sharp
然而,这是高级,如果您对classes、方法、对象、属性没有太多经验,则不容易理解,处理程序等。而且,它甚至不会减少您的工作量。事实上,它的增加是为了可读性和可测试性,如果这是概念验证或实践,您甚至可能不需要这两者。
因此,我的建议是一步一个脚印地学习知识。开发最强大的解决方案是件好事,但如果您刚刚开始,就不是这样了。一次拿起一件,直到你有足够的经验将它们放在一起。
我对编码还很陌生,我希望尽早改掉坏习惯并开始编写干净高效的代码。我正在开发一个引用 API 的控制台应用程序,并且我有一系列深度嵌套的“if”(最高可达 10 层!)。
commonLogic forQuote = new commonLogic();
if (countryRes == CountryDes)
{
//staying in country
try2:
//display reasons for travel
Console.WriteLine("What Best Describes Your Reason For Traveling?");
Console.WriteLine(" ");
Console.WriteLine("1. United States Resident traveling Inside the U.S.");
Console.WriteLine("2. Visiting United States For Business or Pleasure.");
Console.WriteLine("3. Immigrating to The Unites States.");
Console.WriteLine("4. Student, Faculty Member or Scholar With a J-1, F-1, H-3, M-1, or Q-1 Visa.");
Console.WriteLine(" ");
var x = Console.ReadLine();
Console.Clear();
if (x == "1")
{
//US resident
//first print
forQuote.gatherUserData();
}
else if (x == "2")
{
try3:
//visiting the US
Console.WriteLine("What Type of Coverage Do You Need?");
Console.WriteLine(" ");
Console.WriteLine("1. Medical voerage");
Console.WriteLine("2. Trip Cancellation");
var r = Console.ReadLine();
Console.WriteLine(" ");
Console.Clear();
if (r == "1")
{
//medical coverage
Console.WriteLine("What Type of Medical Coverage Do You Want?");
Console.WriteLine(" ");
Console.WriteLine("1. Scheduled benifits");
Console.WriteLine("2. Comprehensive Benifits");
var s = Console.ReadLine();
Console.WriteLine(" ");
Console.Clear();
if (s == "1")
{
//second print
forQuote.gatherUserData();
}
else if (s == "2")
{
//comprehensive benifits
//third print
forQuote.gatherUserData();
}
else
{
//first else
Console.WriteLine("Invalid Input. Please Try Again");
}
}
else if (r == "2")
{
//trip canccelation
//fourth print
forQuote.gatherUserData();
}
else
{
//secondelse
Console.WriteLine("Invalid Input. Please Try Again");
goto try3;
}
}
else if (x == "3")
{
//immigration
//fithprint
forQuote.gatherUserData();
}
else if (x == "4")
{
//students...
//sixthprint
forQuote.gatherUserData();
}
else
{
//thirdelse
Console.WriteLine("Invalid Input. Please try Again");
goto try2;
}
}
这只是 if
总巢穴中的一小部分样本。我做了很多关于清理这个问题的研究,但我很难understanding/using找到我找到的答案。
我在重构时遇到的最大问题是 if
之后的每个都直接依赖于它之前的 if
。
我还对您需要达到每个 if
的输入进行了逻辑分析 table。如果有帮助,我会把它放在这里:
Excel table showing if paths
非常感谢您的帮助,并且解释为什么您的回答提高了可读性和效率也将是极好的。
看这段代码:
bool loop = true;
while(loop)
{
Console.WriteLine("Question");
Console.WriteLine("1. Ans1");
Console.WriteLine("2. Ans2");
Console.WriteLine("3. Exit");
string resp = Console.ReadLine();
switch(resp)
{
case "1":
Console.WriteLine("Ans1 chosen");
break;
case "2":
SomeQuestion();
break;
case "3":
loop = false;
break;
default:
Console.WriteLine("Invalid Input. Please try Again");
break;
}
}
void SomeQuestion()
{
bool loop = true;
while(loop)
{
Console.WriteLine("Question secon level");
Console.WriteLine("1. Ans3");
Console.WriteLine("2. Ans4");
Console.WriteLine("3. Exit");
string resp = Console.ReadLine();
switch(resp)
{
case "1":
Console.WriteLine("Ans1 chosen");
break;
case "2":
break;
case "3":
loop = false;
break;
default:
Console.WriteLine("Invalid Input. Please try Again");
break;
}
}
}
这道题很简单,一道题就说明了思路。
- 而是转到有条件的循环。
- 相反,如果一个开关使代码更具可读性。
我们先分解一些眼前的问题。
goto 语句(错误):
此语句令人困惑,因为它不符合执行流程。它基本上说 "Go to this arbitrary point in code that you have to find"。现在将其乘以 3 或 4,您将得到一个带有许多传送点的迷宫。你会很快迷路。
以下是如何解决此问题的示例:
if(condition)
{
try2:
// do stuff
if(condition2)
{
// Do more stuff
}
else
{
// Report error
goto try2;
}
}
// Replace with:
while(condition)
{
// do stuff
if(condition2)
{
// Do more stuff
break;
}
else
{
// Report error
continue; // Goes to the top of the loop
}
}
这个例子并不完美,从技术上讲你不需要 "continue",但我想解释一下它的用法。
命名约定:
每个class名称、变量名称、方法名称等都需要一个描述性标识符。 "loop" 什么也没告诉我。命名尽可能具有描述性。如果这样做之后仍然存在一些歧义,在定义中使用注释来清除它。
嵌套循环:
好的,这就是你程序的整体设计。不幸的是,询问一堆相关问题的控制台应用程序将会变得混乱。
为什么?
因为 WPF 等用户界面框架可以更好地处理此类逻辑。例如,您的很多逻辑都可以在按钮处理程序和控件属性中处理。
但是,您仍然可以改进您的代码。但是,它需要非常面向对象的设计。我会选择 状态模式 作为开始。
状态模式资源:http://www.dotnettricks.com/learn/designpatterns/state-design-pattern-c-sharp
然而,这是高级,如果您对classes、方法、对象、属性没有太多经验,则不容易理解,处理程序等。而且,它甚至不会减少您的工作量。事实上,它的增加是为了可读性和可测试性,如果这是概念验证或实践,您甚至可能不需要这两者。
因此,我的建议是一步一个脚印地学习知识。开发最强大的解决方案是件好事,但如果您刚刚开始,就不是这样了。一次拿起一件,直到你有足够的经验将它们放在一起。