所以我一直在环顾四周,看起来摆脱大开关案例的正确答案是多态,但我无法弄清楚如何将其从条件变为poplymorphic。这是正确的解决方案吗?
Console.WriteLine(@"Menu");
Console.WriteLine(@"1.Create Account");
Console.WriteLine(@"2.ATM");
Console.WriteLine(@"3.Account info");
Console.Write(@"Please enter your selection: ");
var menuChoice = int.Parse(Console.ReadLine());
switch (menuChoice)
{
case 1:
atm.CreateAccount();
break;
case 2:
//Console.WriteLine(@"1.Deposit Or Withdraw");
Console.WriteLine(@"1.Deposit");
Console.WriteLine(@"2.Withdraw");
Console.Write(@"Please enter your selection: ");
var atmMenuChoice = int.Parse(Console.ReadLine());
switch (atmMenuChoice)
{
case 1:
atm.Deposit();
break;
case 2:
atm.Withdraw();
break;
default:
Console.WriteLine(@"Invalid selection!");
break;
}
break;
case 3:
atm.AccountInfo();
break;
default:
Console.WriteLine(@"Invalid selection!");
break;
}
}
答案 0 :(得分:2)
在这种情况下,我倾向于使用Dictionary<string, Action>
来查找每个输入的内容。
类似的东西:
var actions = new Dictionary<string, Action>
{
{ "1", atm.CreateAccount }
{ "2", AtmSelection } //This would do the same as below with the atmActions dictionary
{ "3", atm.AccountInfo }
}
var atmActions = new Dictionary<string, Action>
{
{ "1", atm.Deposit }
{ "2", atm.Withdraw }
}
var input = GetInput(); //From stdin as you do currently
if (actions.TryGetValue(input, out var action))
{
action();
}
else
{
Console.WriteLine("Invalid Selection");
}
我个人认为这比大量嵌套的switch语句更容易阅读
答案 1 :(得分:0)
当您使用某种序列化框架时,对开关的多态性的偏好通常适用。想象一下,您的int
是一类单身成员的序列化表示,所有这些单身都有一个特定的方法可以对atm
对象进行操作(或visits)。然后你可以反序列化实例并调用该方法:
var foo = deserializer.deserialize(intVal);
foo.doStuff(atm);
还有一个开关涉及,但它在序列化框架内,你不必维护它。如果你想在没有序列化框架的情况下实现类似的模式,你必须自己编写交换机。好处是您可以将开关与逻辑的其余部分分开:
Foo GetFoo(int type) {
// switch on type
}
var foo = GetFoo(intVal);
foo.doStuff(atm);
这种模式是在没有(或没有)函数指针或等价的语言中开发的。在具有函数指针的语言中,int
值的映射到另一个答案中建议的函数将基本上完成相同的事情。
答案 2 :(得分:0)
我可能在这里有点疯狂,但这与斯科特的回答类似。
static IEnumerable<MenuItem> RootMenu;
static void Main(string[] args)
{
RootMenu = BuildRootMenu();
MenuItem.DisplayMenu(RootMenu, new Atm());
}
/// <summary>
/// Creates the entire menu
/// </summary>
static IEnumerable<MenuItem> BuildRootMenu()
{
MenuItem item1 = new MenuItem() { DisplayText = "Create Account", AtmAction = (a) => a.CreateAccount() };
MenuItem item2_1 = new MenuItem() { DisplayText = "Deposit", AtmAction = (a) => a.Deposit() };
MenuItem item2_2 = new MenuItem() { DisplayText = "Withdraw", AtmAction = (a) => a.Withdraw() };
MenuItem item2 = new MenuItem() { DisplayText = "ATM", AtmAction = (a) => MenuItem.DisplayMenu(new List<MenuItem> { item2_1, item2_2 }, a) };
MenuItem item3 = new MenuItem() { DisplayText = "Account Info", AtmAction = (a) => a.CreateAccount() };
return new List<MenuItem> { item1, item2, item3 };
}
class MenuItem
{
public String DisplayText;
public Action<Atm> AtmAction = null;
public void Execute(Atm atm)
{
AtmAction(atm);
DisplayMenu(RootMenu, atm);
}
public static void DisplayMenu(IEnumerable<MenuItem> menuItems, Atm atm)
{
int i = 1;
foreach (var mi in menuItems)
{
Console.WriteLine(i + ": " + mi.DisplayText);
i++;
}
var rk = Console.ReadKey();
menuItems.ToArray()[int.Parse(rk.KeyChar.ToString()) - 1].Execute(atm);
}
}
class Atm
{
public void Deposit()
{
Console.WriteLine("Ran Deposit");
}
public void Withdraw()
{
Console.WriteLine("Ran Withdraw");
}
public void CreateAccount()
{
Console.WriteLine("Ran CreateAccount");
}
public void AccountInfo()
{
Console.WriteLine("Ran AccountInfo");
}