Поддержание модульности в Main()?

Я пишу простую карточную игру "Война" для домашнего задания, и теперь, когда игра работает, я пытаюсь сделать ее более модульной и организованной. Ниже раздел Main() содержащий основную часть программы. Я должен отметить, что курс преподается на C#, но это не курс C#. Скорее, мы изучаем базовую логику и концепции ООП, поэтому я могу не использовать некоторые функции C#.

bool sameCard = true;

while (sameCard)
{
    sameCard = false;
    card1.setVal(random.Next(1,14));        // set card value
    val1 = determineFace(card1.getVal());   // assign 'face' cards accordingly
    suit = suitArr[random.Next(0,4)];       // choose suit string from array
    card1.setSuit(suit);                    // set card suit
    card2.setVal(random.Next(1,14));        // rinse, repeat for card2...
    val2 = determineFace(card2.getVal());    
    suit = suitArr[random.Next(0,4)];        
    card2.setSuit(suit);  

    // check if same card is drawn twice:

    catchDuplicate(ref card1, ref card2, ref sameCard); 
}
Console.WriteLine ("Player: {0} of {1}", val1, card1.getSuit());
Console.WriteLine ("Computer: {0} of {1}", val2, card2.getSuit());

// compare card values, display winner:

determineWinner(card1, card2);   

Итак, вот мои вопросы:

  • Могу ли я использовать циклы в Main() и при этом считать их модульными?
  • Правильно ли написан процесс составления карты?
  • Считается ли плохой практикой печатать сообщения в методе (то есть: determineWinner())?

Я программировал только два семестра, и я хотел бы сформировать хорошие привычки на этом этапе. Любой вклад / совет будет высоко ценится.

Редактировать:

catchDuplicate () теперь является логическим методом, и вызов выглядит так:

sameCard = catchDuplicate(card1, card2);

благодаря @Douglas.

4 ответа

Решение

Могу ли я использовать циклы в Main() и при этом считать их модульными?

Да, ты можешь. Тем не менее, чаще всего, Main в ООП-программах содержится только несколько вызовов методов, которые инициируют основные функции, которые затем сохраняются в других классах.

Правильно ли написан процесс составления карты?

Частично. Если я правильно понимаю ваш код (вы только показываете Main), вы предпринимаете некоторые действия, которые, если они выполнены в неправильном порядке или с неправильными значениями, могут оказаться неудачными. Подумайте об этом так: если вы продаете свою библиотеку классов (не весь продукт, а только ваши классы), каков будет самый простой способ использовать вашу библиотеку для непосвященного пользователя?

Т.е. рассмотрим класс Deck которая содержит колоду карт. При создании он создает все карты и тасует его. Дай ему метод Shuffle перемешать колоду, когда пользователь вашего класса должен перемешать и добавить такие методы, как DrawCard для обработки дилинговых карт.

Далее: у вас есть методы, которые не содержатся в собственном классе, но имеют функциональность, которая была бы лучше в классе. То есть, determineFace лучше подходит для использования в классе Card (при условии, card2 имеет тип Card).

Считается ли плохой практикой печатать сообщения в методе (то есть: defineWinner())?

И да и нет. Если вы хотите, чтобы сообщения были видны только во время тестирования, используйте Debug.WriteLine, В производственной сборке это не будет. Однако когда вы пишете сообщения в рабочей версии, убедитесь, что это ясно из названия метода. То есть, WriteWinnerToConsole или что-то.

Чаще всего этого не делают, потому что: в каком формате вы печатаете информацию? Какой текст должен прийти с этим? Как вы справляетесь с локализацией? Однако, когда вы пишете программу, очевидно, что она должна содержать методы, которые записывают материал на экран (или форму, или веб-страницу). Они обычно содержатся в определенных классах для этой цели. Здесь это может быть класс CardGameX например.

Общие мысли
Подумайте о принципе "у одного метода / функции должна быть только одна задача и только одна задача, и у нее не должно быть побочных эффектов (таких как вычисление квадрата и печать, тогда печать - это побочный эффект)".

Принцип для классов очень высокоуровневый: класс содержит методы, которые логически связаны друг с другом и работают с одним и тем же набором свойств / полей. Пример обратного: Shuffle не должно быть методом в классе Card, Тем не менее, он будет принадлежать логически в классе Deck,

Если основной проблемой вашей домашней работы является создание модульного приложения, вы должны инкапсулировать всю логику в специализированных классах. Каждый класс должен выполнять только одну работу. Функция, играющая с картой, должна быть в классе карты. Функция, которая тянет карты, должна быть другого класса.

Я думаю, что это цель вашей домашней работы, удачи!

Возьмите все советы о "лучших практиках" с долей соли. Всегда думай сам.

Это говорит:

  • Могу ли я использовать циклы в Main() и при этом считать их модульными?

Эти два понятия независимы. Если ваш Main() выполняет только высокоуровневую логику (то есть вызывает другие методы), тогда не имеет значения, делает ли это это в цикле, ведь алгоритм требует цикла. (Вы бы не добавили цикл без необходимости, нет?)

Как правило, если это возможно / практично, сделайте вашу программу самодокументированной. Сделайте его "читабельным", чтобы, если новый человек (или даже вы, через несколько месяцев) посмотрел на него, он мог понять его на любом уровне.

  • Правильно ли написан процесс составления карты?

Нет. Прежде всего, карта никогда не должна выбираться дважды. Для более "модульного" подхода у меня было бы что-то вроде этого:

while ( Deck.NumCards >= 2 )
{
   Card card1 = Deck.GetACard();
   Card card2 = Deck.GetACard();
   PrintSomeStuffAboutACard( GetWinner( card1, card2 ) );
}
  • Считается ли плохой практикой печатать сообщения в методе (то есть: defineWinner())?

Является ли целью determineWinner напечатать сообщение? Если ответ "Нет", то это не вопрос "плохой практики", ваша функция совершенно неверна.

Тем не менее, существует такая вещь, как "отладочная" сборка и "выпускная" сборка. Чтобы помочь вам в отладке приложения и выяснении того, что работает, а что нет, полезно добавить сообщения регистрации.

Убедитесь, что они актуальны и что они не выполняются в сборке "release".

В: Могу ли я использовать циклы в Main() и при этом считать их модульными?

A: Да, вы можете использовать циклы, которые на самом деле не влияют на модульность.

Q: Правильно ли написан процесс составления карты?

A: Если вы хотите быть более модульным, превратите DrawCard в функцию / метод. Возможно, просто напишите DrawCards вместо DrawCard, но тогда возникает вопрос оптимизации по сравнению с модульностью.

Q: Считается ли плохой практикой печатать сообщения в методе (то есть: defineWinner ())?

A: Я бы не сказал, что печать сообщений в методе - это плохая практика, это зависит только от контекста. В идеале сама игра не обрабатывает ничего, кроме игровой логики. Программа может иметь некоторый игровой объект и может считывать состояние с игрового объекта. Таким образом, вы можете технически изменить игру с текстовой на графическую. Я имею в виду, что это идеально для модульности, но это может быть непрактично с учетом крайнего срока. Вы всегда должны решить, когда вам следует пожертвовать лучшей практикой, потому что не хватает времени. К сожалению, это слишком часто встречается.

Отделите игровую логику от презентации. В такой простой игре это ненужная зависимость.

Другие вопросы по тегам