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