0

来自程序背景,我在设计基于菜单的控制台应用程序和用户输入验证时遇到了一个概念块。我的目标是显示一个启动其他进程的菜单。我想在菜单上将用户输入限制为 1、2 或 3。

在程序语言中,我会做这样的伪代码:

10 print "Make a choice"
20 choice = [dataFromKeyboard]
30 if choice < 4 && choice > 0
40    then 10
50    else 60
60 process valid choices

而且无论我尝试什么,在设计 OO 程序时我都无法忘记这一点。考虑(简化为仅包括 3 个菜单项):

class Menu
{
    public static void Main(String[] args)
    {
        DisplayMenu thisdm = new DisplayMenu;
        int menuChoice = thisdm.displayMenu();
        ProcessMenu thispm = new ProcessMenu();
        thispm.processMenu(menuChoice);
    }
}

class DisplayMenu
{
    public int displayMenu()
    {
        Console.WriteLine("1 - foo3");
        Console.WriteLine("2 - foo2");
        Console.WriteLine("3 - foo3");
        Console.WriteLine("choose");
        String choice = Console.ReadLine();
        int intChoice = Convert.ToInt32(choice);
        return intChoice;
    }
}

class ProcessMenu
{
    public void processMenu(int choice)
    {
        switch(choice)       
        {
        case 1:   
            foo1();
            break;                  
        case 2:            
            foo2();
            break;
        case 3:            
            foo3();;
            break;         
        default:            
            Console.WriteLine("Invalid selection. Please select 1, 2, or 3.");            
            break;      
        }
    }
}

所以这就是我卡住的地方。我只是无法用一种简单而优雅的方式来验证我的用户输入,这是从 OO 而不是程序的角度来看的。

假设我在 中进行验证DisplayMenu,我将在读取输入后进行验证。但如果结果无效,我该如何重新请求有效输入,因为我已经调用了displayMenu方法 from Main

我已经玩while了大约一个小时的循环,像这样:

intChoice = 0;
[print the menu]
while ((intChoice<1) || (intChoice>3))
Console.WriteLine("Please make a valid choice from the menu");
choice = Console.ReadLine();
etc.

但似乎找不到我可以控制用户输入的最佳位置。

我怀疑这是因为我在程序上思考,而不是足够面向对象。有人有任何提示或意见可以帮助我解决这个问题吗?

4

4 回答 4

1

扩展@AlexeiLevenkov的“将你的课程转 90 度”的建议,我更进一步,创建了一个“模块化”控制台应用程序的示例:

class Program
{
    static void Main(string[] args)
    {
        //Retrieve all Module types in the current Assembly.
        var moduletypes = Assembly.GetExecutingAssembly()
                                  .GetTypes()
                                  .Where(x => x.IsSubclassOf(typeof(ConsoleModule)));

        //Create an instance of each module
        var modules = moduletypes.Select(Activator.CreateInstance)
                                 .OfType<ConsoleModule>()
                                 .OrderBy(x => x.Id)
                                 .ToList();


        int SelectedOption = -1;

        while (SelectedOption != 0)
        {
            //Show Main Menu    
            Console.Clear();
            Console.WriteLine("Please Select An Option:\n");
            modules.ForEach(x => Console.WriteLine(string.Format("{0} - {1}", x.Id, x.DisplayName)));
            Console.WriteLine("0 - Exit\n");
            int.TryParse(Console.ReadLine(), out SelectedOption);

            //Find Module by Id based on user input
            var module = modules.FirstOrDefault(x => x.Id == SelectedOption);

            if (module != null)
            {
                //Execute Module
                Console.Clear();
                module.Execute();
                Console.WriteLine("Press Enter to Continue...");
                Console.ReadLine();
            }
        }
    }

控制台模块类:

public abstract class ConsoleModule
{
    public int Id { get; set; }

    public string DisplayName { get; set; }

    public abstract void Execute();

}

一些示例模块:

public class EnterUserNameModule : ConsoleModule
{
    public EnterUserNameModule()
    {
        Id = 2;
        DisplayName = "User Name";
    }

    public static string UserName { get; set; }

    public override void Execute()
    {
        Console.WriteLine("Please Enter Your Name: ");
        UserName = Console.ReadLine();
    }
}

public class HelloWorldModule: ConsoleModule
{
    public HelloWorldModule()
    {
        Id = 1;
        DisplayName = "Hello, World!";
    }

    public override void Execute()
    {
        Console.WriteLine("Hello, " + (EnterUserNameModule.UserName ?? "World") + "!");
    }
}

public class SumModule: ConsoleModule
{
    public SumModule()
    {
        Id = 3;
        DisplayName = "Sum";
    }

    public override void Execute()
    {
        int number = 0;
        Console.Write("Enter A Number: ");
        if (int.TryParse(Console.ReadLine(), out number))
            Console.WriteLine("Your number plus 10 is: " + (number + 10));
        else
            Console.WriteLine("Could not read your number.");
    }
}

结果:

在此处输入图像描述

它使用一点点反射来查找从ConsoleModule当前程序集中派生的所有类型,然后显示一个包含所有这些选项(实际上是此类中的属性)的菜单,并在Execute()选择适当的选项时调用该方法。更倾向于OO的思维方式。

于 2013-05-16T03:17:56.130 回答
0

让你的processMenu函数返回某种指标。您可以为此使用异常,但这有点矫枉过正。

public bool processMenu(int choice)
{
    ....
}

如果选择可以接受,则返回true,否则返回false。然后:

public static void Main(String[] args)
{
    DisplayMenu thisdm = new DisplayMenu;
    ProcessMenu thispm = new ProcessMenu();

    int menuChoice;

    do {
        menuChoice = thisdm.displayMenu();
    } while( !thispm.processMenu(menuChoice) );
}
于 2013-05-16T02:16:24.817 回答
0

你正在做的方式应该改变。无论如何,与您的问题一样,这可以解决:

DisplayMenu thisdm = new DisplayMenu();

int menuChoice = -1;

while (menuChoice < 1 || menuChoice > 3)
{
    Console.WriteLine("enter valid choice");
    menuChoice = thisdm.displayMenu();
}

ProcessMenu thispm = new ProcessMenu();
thispm.processMenu(menuChoice);
于 2013-05-16T02:31:48.100 回答
0

代码如下:

 class Program
{
    static void Main(string[] args)
    {
        DisplayMenu thisdm = new DisplayMenu();
        ProcessMenu thispm = new ProcessMenu();

        thisdm.displayMenu();
        int menuChoice = thispm.GetChoice();
        thispm.processMenu(menuChoice);

        Console.Read();
    }

}

class DisplayMenu
{
    public void displayMenu()
    {
        Console.WriteLine("1 - foo3");
        Console.WriteLine("2 - foo2");
        Console.WriteLine("3 - foo3");
        Console.WriteLine("choose");

    }
}

class ProcessMenu
{
    public int GetChoice()
    {
        String choice = Console.ReadLine();
        int intChoice = Convert.ToInt32(choice);

        while (!Validate(intChoice))
        {
            Console.WriteLine("Invalid selection. Please select 1, 2, or 3.");
            choice = Console.ReadLine();
            intChoice = Convert.ToInt32(choice);
        }

        return intChoice;
    }

    public void processMenu(int choice)
    {

        switch (choice)
        {
            case 1:
                //foo1();
                break;
            case 2:
                //foo2();
                break;
            case 3:
                //foo3(); ;
                break;
            default:
                //Console.WriteLine("Invalid selection. Please select 1, 2, or 3.");
                break;
        }
    }

    private int[] forChoices=new int[]{1,2,3};

    private  bool  Validate(int choice)
    {
        if(forChoices.Contains(choice))
        {
            return true;
        }

        return false;
    }
}
于 2013-05-16T02:34:48.747 回答