Я новичок в программировании и затрудняюсь с простой задачей приготовления кофе на C#

#c#

#c#

Вопрос:

Я только начал немного заниматься C # и поставил перед собой задачу создать простую консольную программу для кофейни, которая просто составляет список того, что вы хотите, а затем возвращает его вам, когда вы все это вводите. Единственный способ, который я нашел до сих пор, который хорошо работал для меня, заключался в том, чтобы сделать это:

 string Tea = "tea";
string Option1 = Console.ReadLine();

if ((Option1 == Tea)
        {
            Console.Clear();

            //Confirmation Text
            Console.WriteLine("So you want a "   Option1   ".");

            //Second Question
            Console.WriteLine("Do you want milk, sugar, both or none?");

            //Second Option
            string Option2 = Console.ReadLine();

            //Milk
            if (string.Equals(Milk, Option2))
            {
                Console.Clear();
                //Confirmation Text
                Console.WriteLine("So you want a "   Option1   " with "   Option2   ".");

                //Third Question
                Console.WriteLine("And so what size will that be, small, medium, or large?");

                //Third Option
                string Option3 = Console.ReadLine();

                if (string.Equals(Large, Option3))
                {
                    Console.Clear();
                    //Last Confirmation
                    Console.WriteLine("Here is your "   Option3   " "   Option1   " with "   Option2   ".");
                    Console.ReadKey();

                }
                else if (string.Equals(Medium, Option3))
                {
                    Console.Clear();
                    //Last Confirmation
                    Console.WriteLine("Here is your "   Option3   " "   Option1   " with "   Option2   ".");
                    Console.ReadKey();

                }
                else if (string.Equals(Small, Option3))
                {
                    Console.Clear();
                    //Last Confirmation
                    Console.WriteLine("Here is your "   Option3   " "   Option1   " with "   Option2   ".");
                    Console.ReadKey();

                }
                else Console.WriteLine("Sorry that is not one of our sizes.");

            }
  

Но это кажется слишком большим количеством кода для выполнения простой задачи, поскольку мне постоянно приходится повторять что-то снова и снова. Я пытался найти другие методы, но, похоже, не могу понять, как вы внедряете их в то, что я пытаюсь сделать. А также реализация цикла также была целью, но я тоже не мог этого понять.

Комментарии:

1. Я не уверен на 100%, в чем проблема, с которой вы столкнулись. Если вы хотите найти лучший способ представления такого сценария, вы можете захотеть взглянуть на шаблон декоратора.

Ответ №1:

Как правило, при разработке программного обеспечения, если вы повторно используете один и тот же код снова и снова, вам следует перенести этот код в метод.

Мое следующее решение далеко от совершенства, потому что мне пришлось использовать статические методы из-за доступа к методам, которые я написал из «основного» класса, который сам по себе статичен. Для меня было бы намного лучше создать класс для обработки логики и создания экземпляра этого класса.

Учитывая, что вы говорите, что вы новичок в программировании, я избегал делать что-либо, что могло бы сбить с толку, и вместо этого пытался просто повторно использовать код, где это возможно, просто для демонстрации повторного использования кода.

Вот мое решение вашей проблемы:

 using System;

class MainClass {
  public static void Main (string[] args) {

    string Option1 = Console.ReadLine();

    if (Option1 == "Tea")
    {
       string[] questionSet1 = { "So you want a "   Option1   ".", 
                                 "Do you want milk, sugar, both or none?"};

       //Confirmation Text
       string Option2 = PrintTextArray(questionSet1);

       //Milk
       if (Option2.Equals("Milk"))
       {
          string[] questionSet2 = { "So you want a "   Option1   " with "   Option2   ".", 
                                    "And so what size will that be, small, medium, or large?"};
          //Confirmation Text
          string Option3 = PrintTextArray(questionSet2);

          if (Option3.Equals("Large"))
          {
             //Last Confirmation
             PrintText("Here is your "   Option3   " "   Option1   " with "   

Option2   ".");

           }
           else if (Option3.Equals("Medium"))
           {
              //Last Confirmation
              PrintText("Here is your "   Option3   " "   Option1   " with "   Option2   ".");

           }
           else if (Option3.Equals("Small"))
           {
              //Last Confirmation
              PrintText("Here is your "   Option3   " "   Option1   " with "   Option2   ".");

           }
           else Console.WriteLine("Sorry that is not one of our sizes.");

         }
      }
  }

  private static string PrintText(string textToPrint)
  {
    string[] textListToPrint = { textToPrint };

    return PrintTextArray(textListToPrint);
  }

  private static string PrintTextArray(string[] textListToPrint)
  {
      Console.Clear();

      for(int i = 0; i < textListToPrint.Length; i  )
      {
        Console.WriteLine(textListToPrint[i]);
      }

      return Console.ReadLine();
  }
}
  

В основном я написал два метода, один из которых является перегруженным методом, который принимает строку или массив строк, распечатывает их и возвращает следующее нажатие клавиши.

Я не собираюсь сидеть и притворяться, что это идеальное решение, потому что метод должен выполнять только одну вещь в соответствии с принципом единой ответственности, но, опять же, учитывая, что вы новичок в программировании, я пытался избежать чрезмерного усложнения. Я бы настоятельно рекомендовал изучить принципы SOLID.

Наконец, пара указателей, в C # метод должен быть объявлен, начиная с заглавной буквы для его имени, а переменные должны быть объявлены с использованием соглашения о верблюжьем регистре. Более подробную информацию о camel case можно найти здесь

Ответ №2:

Это действительно много дублированного кода для простой программы.

Вот несколько предложений, чтобы прояснить намерение и упростить реализацию.

1. Отделите свое состояние от потока приложения.

Прямо сейчас, чем больше опций вы бы добавили, тем глубже стали бы ваши if условия.

Попробуйте создать типы данных, которые представляют ваше состояние. Вот предложение:

 public enum OrderType
{
    Tea,
    Coffee
}

public class Order
{       
    /// <summary>
    /// The type of this order (either tea or coffee).
    /// </summary>
    public OrderType Type { get; set; }

    /// <summary>
    /// The list of all options for your order. (Example ["Milk", "Sugar"])
    /// </summary>
    public List<string> Options { get; } = new List<string>();
}
  

2. Уточните поток / намерение вашего приложения

Используйте методы с понятными именами, чтобы создать поток вашего приложения. Вот пример:

 static void Main(string[] args)
{
    while (true)
    {
        var order = new Order();
        Console.WriteLine("Hello, would you like tea or coffee?");
        // Read the order type from the user.
        order.Type = ReadOrderType();

        // Get the options available for that order type.
        var availableOptions = GetAvailableOptionsFor(order.Type);

        // Print the order type and the available options for that order type.
        Console.WriteLine($"{order.Type}, all right! Would you like something in it?");

        // Get the chosen options from the user.
        order.Options = ReadChosenOptions(order.Type, availableOptions);

        if (order.Options.Any())
        {
            // Print the order with options.
            Console.WriteLine($"Okay so that's a {order.Type} with {string.Join(", ", order.Options)}. See ya!");
        }
        else
        {
            // Print the order without options.
            Console.WriteLine($"Okay so that's a plain {order.Type}. Have a great day!");
        }
    }
}
  

3. Создайте методы для чтения пользовательского ввода.

Это позволяет повторно использовать код вместо его повторения. Вот пример:

 private static OrderType ReadOrderType()
{
    var orderType = Console.ReadLine();
    switch (orderType.ToUpper())
    {
        case "TEA":
            return OrderType.Tea;
        case "COFFEE":
            return OrderType.Coffee;
        default:
            Console.WriteLine($"I'll assume coffee.");
            return OrderType.Coffee;
    }
}
  

Пример полного кода

Вот полное консольное приложение, которое я написал, чтобы помочь мне ответить.

 class Program
{
    static void Main(string[] args)
    {
        while (true)
        {
            var order = new Order();
            Console.WriteLine("Hello, would you like tea or coffee?");
            // Read the order type from the user.
            order.Type = ReadOrderType();

            // Get the options available for that order type.
            var availableOptions = GetAvailableOptionsFor(order.Type);

            // Print the order type and the available options for that order type.
            Console.WriteLine($"{order.Type}, all right! Would you like something in it?");

            // Get the chosen options from the user.
            order.Options = ReadChosenOptions(order.Type, availableOptions);

            if (order.Options.Any())
            {
                // Print the order with options.
                Console.WriteLine($"Okay so that's a {order.Type} with {string.Join(", ", order.Options)}. See ya!");
            }
            else
            {
                // Print the order without options.
                Console.WriteLine($"Okay so that's a plain {order.Type}. Have a great day!");
            }
        }
    }

    private static List<string> ReadChosenOptions(OrderType orderType, List<string> availableOptions)
    {
        var options = new List<string>();
        bool areMoreOptionsDesired = ReadYesOrNo();
        if (!areMoreOptionsDesired)
        {
            // Return no options;
            return options;
        }

        while (areMoreOptionsDesired)
        {
            Console.WriteLine($"Here are our options: {string.Join(", ", availableOptions)}.");
            var option = ReadOption(availableOptions);
            if (option != null)
            {
                options.Add(option);
                Console.WriteLine($"So far you got a {orderType} with {string.Join(", ", options)}.");
            }

            Console.WriteLine($"Would you like something else in it?");
            areMoreOptionsDesired = ReadYesOrNo();
        }

        return options;
    }

    private static string ReadOption(List<string> availableOptions)
    {
        var input = Console.ReadLine();
        if (availableOptions.Contains(input, StringComparer.OrdinalIgnoreCase))
        {
            return input;
        }
        else
        {
            Console.WriteLine($"{input} is not a valid option.");
            return null;
        }
    }

    private static bool ReadYesOrNo()
    {
        var desicion = Console.ReadLine();
        if (desicion.ToUpper() == "YES")
        {
            return true;
        }
        else if (desicion.ToUpper() == "NO")
        {
            return false;
        }
        else
        {
            Console.WriteLine($"I'll take that as a "no".");
            return false;
        }
    }

    private static List<string> GetAvailableOptionsFor(OrderType orderType)
    {
        switch (orderType)
        {
            default:
            case OrderType.Tea:
                return new List<string>() { "Milk", "Sugar" };
            case OrderType.Coffee:
                return new List<string>() { "Milk", "Sugar", "Cream" };
        }
    }

    private static OrderType ReadOrderType()
    {
        var orderType = Console.ReadLine();
        switch (orderType.ToUpper())
        {
            case "TEA":
                return OrderType.Tea;
            case "COFFEE":
                return OrderType.Coffee;
            default:
                Console.WriteLine($"I'll assume coffee.");
                return OrderType.Coffee;
        }
    }
}

public enum OrderType
{
    Tea,
    Coffee
}

public class Order
{
    /// <summary>
    /// The type of this order (either tea or coffee).
    /// </summary>
    public OrderType Type { get; set; }

    /// <summary>
    /// The list of all options for your order. (Example ["Milk", "Sugar"])
    /// </summary>
    public List<string> Options { get; set; }
}
  

Ответ №3:

Поскольку вы только начинаете, я бы пока проигнорировал объектно-ориентированное программирование и сосредоточился на том, как сделать ваш код не только простым для понимания, но и достаточно простым для добавления новых напитков в вашу систему.

Первое, что я бы сделал, это создал функцию, которая отображает список опций, которые будут представлены пользователю, и не позволяет им уйти, пока они не введут правильный ответ из этого списка опций. Это позволит вам сосредоточиться на «потоке» основной программы и не загромождать ее повторяющимися жестко запрограммированными меню для каждой части системы.

Вот функция, которая получает приглашение и строковый массив опций:

 static int getMenuResponse(string prompt, string[] options)
{
    while(true)
    {
        Console.WriteLine();
        Console.WriteLine(prompt);
        for(int i=0; i<options.Length; i  )
        {
            Console.WriteLine($"[{i 1}] {options[i]}");
        }
        Console.Write("Your choice: ");
        string response = Console.ReadLine();
        int option;
        if (int.TryParse(response, out option) amp;amp; option>=1 amp;amp; option<=options.Length)
        {
            return (option-1);
        }
        Console.WriteLine("Invalid Selection. Please try again.");
        Console.WriteLine();
    }
}
  

Примером использования может быть:

 string prompt = "How are you feeling today?";
string[] feelings = new string[] { "Good", "Indifferent", "Bad" };
int response = getMenuResponse(prompt, feelings);

Console.WriteLine();
Console.WriteLine("You are feeling "   feelings[response]);
  

Вывод:

введите описание изображения здесь

Имея это в виду, вы можете смоделировать свой магазин как набор меню, представленных массивами строк. Здесь я настроил напитки, размеры и другой набор элементов, которые можно добавлять к каждому напитку:

 string[] drinks = new string[] {"Exit", "Tea", "Coffee", "Smoothie"};
string[] drinkSizes = new string[] { "Small", "Medium", "Large" };

string[] teaOptions = new string[] { "Done", "Milk", "Sugar" };
string[] coffeeOptions = new string[] { "Done", "Creamer", "Sugar", "Vanilla Syrup", "Hazelnut Syrup"};
string[] smoothieOptions = new string[] { "Done", "Strawberry", "Banana", "Blueberry" };
  

Мы можем использовать словарь, чтобы связать каждый список опций с соответствующим названием напитка:

 Dictionary<string, string[]> drinkOptions = new Dictionary<string, string[]>();
drinkOptions.Add("Tea", teaOptions);
drinkOptions.Add("Coffee", coffeeOptions);
drinkOptions.Add("Smoothie", smoothieOptions);
  

Это позволит нам получить список элементов, которые могут быть добавлены к каждому соответствующему напитку.

Далее мы объявим некоторые переменные для отслеживания текущего напитка, размера и списка добавленных элементов:

 string size;
string drink;            
List<string> options = new List<string>();
  

В рамках настройки наших меню мы теперь будем использовать циклы do … while для запроса типа и размера напитка. Внутри этого мы будем использовать другой внутренний do...while цикл, позволяющий добавлять в напиток столько элементов, сколько пожелает пользователь:

 bool exit = false;
int option;
do
{
    Console.WriteLine();
    Console.WriteLine("Welcome to The Drink Shop!");

    option = getMenuResponse("What drink would you like?", drinks);                
    exit = (option == 0);
    if (!exit)
    {
        drink = drinks[option];

        options.Clear();
        if (drinkOptions.ContainsKey(drink))
        {
            string[] curOptions = drinkOptions[drink];
            do
            {
                option = getMenuResponse("What would you like in your "   drink   "?", curOptions);
                if (option != 0)
                {
                    string itemToAdd = curOptions[option];
                    Console.WriteLine();
                    if (!options.Contains(itemToAdd))
                    {
                        options.Add(itemToAdd);
                        Console.WriteLine(itemToAdd   " added.");
                    }
                    else
                    {

                        Console.WriteLine(itemToAdd   " previously added.");
                    }
                    Console.WriteLine("Current Items: "   string.Join(", ", options));
                }
            } while (option != 0);

            option = getMenuResponse("What size would you like?", drinkSizes);
            size = drinkSizes[option];

            string optionsAdded = "Nothing Added";
            if (options.Count > 0)
            {
                optionsAdded = String.Join(", ", options);
            }
            Console.WriteLine();
            Console.WriteLine("You have ordered a "   size   " "   drink   " with: "   optionsAdded);
        }
        else
        {
            Console.WriteLine();
            Console.WriteLine("Error: Options missing for "   drink   "!");
        }                    
    }
} while (!exit);
  

Пример запущенной программы:

введите описание изображения здесь

Вот вся программа вместе:

 class Program
{

    static void Main(string[] args)
    {
        string[] drinks = new string[] {"Exit", "Tea", "Coffee", "Smoothie"};
        string[] drinkSizes = new string[] { "Small", "Medium", "Large" };

        string[] teaOptions = new string[] { "Done", "Milk", "Sugar" };
        string[] coffeeOptions = new string[] { "Done", "Creamer", "Sugar", "Vanilla Syrup", "Hazelnut Syrup"};
        string[] smoothieOptions = new string[] { "Done", "Strawberry", "Banana", "Blueberry" };

        Dictionary<string, string[]> drinkOptions = new Dictionary<string, string[]>();
        drinkOptions.Add("Tea", teaOptions);
        drinkOptions.Add("Coffee", coffeeOptions);
        drinkOptions.Add("Smoothie", smoothieOptions);

        string size;
        string drink;            
        List<string> options = new List<string>();

        bool exit = false;
        int option;
        do
        {
            Console.WriteLine();
            Console.WriteLine("Welcome to The Drink Shop!");

            option = getMenuResponse("What drink would you like?", drinks);                
            exit = (option == 0);
            if (!exit)
            {
                drink = drinks[option];

                options.Clear();
                if (drinkOptions.ContainsKey(drink))
                {
                    string[] curOptions = drinkOptions[drink];
                    do
                    {
                        option = getMenuResponse("What would you like in your "   drink   "?", curOptions);
                        if (option != 0)
                        {
                            string itemToAdd = curOptions[option];
                            Console.WriteLine();
                            if (!options.Contains(itemToAdd))
                            {
                                options.Add(itemToAdd);
                                Console.WriteLine(itemToAdd   " added.");
                            }
                            else
                            {

                                Console.WriteLine(itemToAdd   " previously added.");
                            }
                            Console.WriteLine("Current Items: "   string.Join(", ", options));
                        }
                    } while (option != 0);

                    option = getMenuResponse("What size would you like?", drinkSizes);
                    size = drinkSizes[option];

                    string optionsAdded = "Nothing Added";
                    if (options.Count > 0)
                    {
                        optionsAdded = String.Join(", ", options);
                    }
                    Console.WriteLine();
                    Console.WriteLine("You have ordered a "   size   " "   drink   " with: "   optionsAdded);
                }
                else
                {
                    Console.WriteLine();
                    Console.WriteLine("Error: Options missing for "   drink   "!");
                }                    
            }
        } while (!exit);

        Console.WriteLine();
        Console.WriteLine("Goodbye!");
        Console.WriteLine();
        Console.Write("Press Enter to Quit...");
        Console.ReadLine();
    }

    static int getMenuResponse(string prompt, string[] options)
    {
        while(true)
        {
            Console.WriteLine();
            Console.WriteLine(prompt);
            for(int i=0; i<options.Length; i  )
            {
                Console.WriteLine($"[{i 1}] {options[i]}");
            }
            Console.Write("Your choice: ");
            string response = Console.ReadLine();
            int option;
            if (int.TryParse(response, out option) amp;amp; option>=1 amp;amp; option<=options.Length)
            {
                return (option-1);
            }
            Console.WriteLine("Invalid Selection. Please try again.");
            Console.WriteLine();
        }
    }

}
  

Из комментариев:

Не могли бы вы немного объяснить, как работает функция? Я понимаю, что делают определенные части, но не все.

Конечно, я добавил несколько комментариев в приведенный ниже код:

 static int getMenuResponse(string prompt, string[] options)
{
    while(true) // we keep asking for a number until we've gotten valid input
    {
        Console.WriteLine();
        Console.WriteLine(prompt); // display the prompt 

        // display each item from the passed in string array,
        // with "1", "2", "3", etc in front of it
        for(int i=0; i<options.Length; i  )
        {
            // the output below is using "string interpolation"
            Console.WriteLine($"[{i 1}] {options[i]}");
            // the line above could instead be written as:
            // Console.WriteLine("["   (i 1)   "] "   options[i]);
        }

        // get a STRING response from the user
        Console.Write("Your choice: ");
        string response = Console.ReadLine();

        // attempt to convert the string into a valid integer
        // int.TryParse() returns true if successful, otherwise false
        // if successful, AND the integer is between 1 and
        // the number of choices in the string array, 
        // then return the zero based index number representing their choice
        int option;
        if (int.TryParse(response, out option) amp;amp; option>=1 amp;amp; option<=options.Length)
        {
            return (option-1);
        }

        // if we get here, then the user input was not a valid integer
        // and/or was outside the range of valid choices from the menu
        Console.WriteLine("Invalid Selection. Please try again.");
        Console.WriteLine();

    } // end of the while loop - go back to the top and repeat
}
  

Комментарии:

1. Большое спасибо за это, я не думал, что люди зайдут так далеко, чтобы помочь

2. Нет проблем. Задавайте столько вопросов, сколько хотите, если вам нужно разъяснение того, что что-либо делает.

3. Не могли бы вы немного объяснить, как работает функция? Я понимаю, что делают определенные части, но не все.

4. Я добавил небольшую правку внизу с кодом функции, снабженным комментариями.

Ответ №4:

Я бы сгенерировал XML-файл со всей информацией: доступные элементы, все возможные дополнения, взаимосвязь между элементами, порядок.. возможно, стоимость и вся «информация». Первая задача — создать этот XML-файл, который зависит от вида информации, с которой вам нужно иметь дело. Затем код C # должен загрузить этот xml и предоставить пользователю опции, записать ответы и так далее. Таким образом, вы правильно отделили информацию от логики. Затем вы можете добавлять элементы в XML-файл.. переведите это на другие языки просто, без необходимости изменять логическую часть. А также измените логику (замените консоль на какой-нибудь пример winform por) без изменения XML-файла. Немного сложнее с самого начала, но гораздо более мощный и управляемый в долгосрочной перспективе.