摆脱一个大的开关案件

时间:2018-01-24 23:34:34

标签: c# oop object switch-statement polymorphism

所以我一直在环顾四周,看起来摆脱大开关案例的正确答案是多态,但我无法弄清楚如何将其从条件变为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;
            }
        }

3 个答案:

答案 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");
  }