Объединение шаблонного метода со стратегией

14

Задача моего класса по разработке программного обеспечения - разработать приложение, которое может играть в различные формы конкретной игры. Рассматриваемая игра - Манкала, некоторые из этих игр называются Вари или Калах. Эти игры отличаются в некоторых аспектах, но для моего вопроса важно знать, что игры могут отличаться в следующем:

  • Способ обработки результата перемещения
  • То, как определяется конец игры
  • Способ определения победителя

Первое, что мне пришло в голову, чтобы разработать это, это использовать шаблон стратегии, у меня есть вариации в алгоритмах (фактические правила игры). Дизайн может выглядеть так: введите описание изображения здесь

Тогда я подумал про себя, что в игре Манкала и Вари способ определения победителя точно такой же, и код будет продублирован. Я не думаю, что это по определению нарушение принципа «одно правило, одно место» или принцип «СУХОЙ», поскольку изменение правил для Mancala не будет автоматически означать, что правило также должно быть изменено в Wari. Тем не менее, по отзывам, полученным от моего профессора, у меня сложилось впечатление найти другой дизайн.

Я тогда придумал это: введите описание изображения здесь

Каждая игра (Mancala, Wari, Kalah, ...) будет просто иметь атрибут типа интерфейса каждого правила, то есть, WinnerDeterminerи если есть версия Mancala 2.0, которая совпадает с Mancala 1.0, за исключением того, как определяется победитель, она может просто используйте версии Mancala.

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

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

  • кладите камни в лунки (это одинаково для всех игр, поэтому будет реализовано в самом методе шаблона)
  • определить результат переезда
  • определить, закончилась ли игра из-за предыдущего хода
  • если игра закончилась, определите, кто выиграл

Эти три последних шага - все в моей стратегии, описанной выше. У меня много проблем с объединением этих двух. Одним из возможных решений, которое я нашел, было бы отказаться от шаблона стратегии и сделать следующее: введите описание изображения здесь

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

Я также не могу определить, кто будет отвечать за создание TurnTemplateобъекта, в то время как с помощью шаблона стратегии я чувствую, что у меня есть семейства объектов (три правила), которые я мог бы легко создать, используя абстрактный шаблон фабрики. Я бы тогда иметь MancalaRuleFactory, WariRuleFactoryи т.д. , и они будут создавать правильные примеры правил и руки меня обратно RuleSetобъект.

Допустим, я использую шаблон стратегии + абстрактная фабрика, и у меня есть RuleSetобъект, в котором есть алгоритмы для трех правил. Единственный способ, которым я чувствую, что все еще могу использовать шаблонный шаблонный метод с этим, состоит в том, чтобы передать этот RuleSetобъект моему TurnTemplate. Проблема, которая возникает тогда, в том, что мне никогда не понадобятся мои конкретные реализации TurnTemplate, эти классы устареют. В моих защищенных методах TurnTemplateя мог просто позвонить ruleSet.determineWinner(). Как следствие, TurnTemplateкласс больше не будет абстрактным, а должен стать конкретным, тогда он все еще будет шаблоном метода шаблона?

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

Mekswoll
источник
1
Я бы сказал, что ваше мышление в значительной степени Если отзывы, которые вы получаете от своего профессора, не подтверждают это, попросите его / ее указать на недостатки или дать подсказку о том, что он (она) в ответе. Хватит пытаться читать мысли. Предположить, что ваш профессор (а затем и ваши пользователи) хотят что-то худшее, что вы можете сделать.
Марьян Венема
« ... в игре Манкала и Вари способ определения победителя точно такой же, и код будет дублирован. » Почему это означает, что код дублируется? Просто позвольте обоим классам вызывать одну и ту же функцию.
D Drmmr

Ответы:

6

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

В своем первом дизайне вы объявляете RuleInterfaceсебя интерфейсом, который определяет, как обрабатывать ход каждого игрока, как определять, закончена ли игра и как определить победителя после ее окончания. Похоже, что это действительный интерфейс для семейства игр, которые испытывают изменения. Однако, в зависимости от игр, вы можете дублировать код. Я бы согласился с тем, что гибкость в изменении правил одной игры - это хорошо, но я бы также сказал, что дублирование кода ужасно для дефектов. Если вы копируете / вставляете дефектный код между реализациями, и в одной из них есть ошибка, теперь у вас есть несколько ошибок, которые необходимо исправить в разных местах. Если вы переписываете реализации в разное время, вы можете вносить дефекты в разных местах. Ни то, ни другое не желательно.

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

Твой третий дизайн мне нравится больше всего. Моя единственная проблема в том, что это не на должном уровне абстракции. Прямо сейчас вы, кажется, моделируете поворот. Я бы порекомендовал подумать о разработке игры. Учтите, что у вас есть игроки, которые делают ходы на доске, используя камни. Ваша игра требует присутствия этих актеров. Оттуда ваш алгоритм не является, doTurn()но playGame(), который идет от начального хода до последнего хода, после которого он заканчивается. После каждого хода игрока он корректирует состояние игры, определяет, находится ли игра в конечном состоянии, и, если это так, определяет победителя.

Я бы порекомендовал присмотреться к вашим первым и третьим проектам и поработать с ними. Это также может помочь мыслить с точки зрения прототипов. Как будут выглядеть клиенты, использующие эти интерфейсы? Есть ли смысл в одном подходе к реализации клиента, который на самом деле собирается создать игру и играть в нее? Вы должны понять, с чем это взаимодействует. В вашем конкретном случае это Gameкласс и любые другие связанные элементы - вы не можете разрабатывать в отдельности.


Поскольку вы упомянули, что вы студент, я хотел бы поделиться некоторыми моментами из того времени, когда я был ТА для курса по разработке программного обеспечения:

  • Шаблоны - это просто способ захвата вещей, которые работали в прошлом, но абстрагирование их до такой степени, что они могут быть использованы в других проектах. Каждый каталог шаблонов дизайна дает имя шаблону, объясняет его намерения и место его использования, а также ситуации, когда он в конечном итоге будет ограничивать ваш дизайн.
  • Дизайн приходит с опытом. Лучший способ добиться успеха в дизайне - не просто сосредоточиться на аспектах моделирования, но понять, что входит в реализацию этой модели. Самый элегантный дизайн полезен, если его нелегко реализовать или он не вписывается в общий дизайн системы или других систем.
  • Очень немногие дизайны являются «правильными» или «неправильными». Пока дизайн соответствует требованиям системы, это не может быть неправильно. Как только каждое требование сопоставляется с некоторым представлением о том, как система будет соответствовать этому требованию, проект не может быть неправильным. На данный момент это только качественно о таких понятиях, как гибкость или возможность повторного использования, тестируемость или ремонтопригодность.
Томас Оуэнс
источник
Спасибо за отличный совет, особенно ваше мнение о том, что он был на неправильном уровне абстракции. Я изменил его сейчас, GameTemplateкоторый чувствует себя намного лучше. Это также позволяет мне комбинировать фабричный метод для инициализации игроков,
игрового
3

Ваше замешательство оправдано. Дело в том, что шаблоны не являются взаимоисключающими.

Шаблонный метод является основой для множества других шаблонов, таких как Стратегия и Состояние. По сути, интерфейс Strategy содержит один или несколько шаблонных методов, каждый из которых требует, чтобы все объекты, реализующие стратегию, имели (как минимум) что-то вроде метода doAction (). Это позволяет заменять стратегии друг на друга.

В Java интерфейс - это не что иное, как набор методов шаблона. Аналогично, любой абстрактный метод по сути является шаблонным методом. Этот образец (среди прочих) был хорошо известен разработчикам языка, поэтому они его встроили.

@ThomasOwens предлагает отличные советы по подходу к вашей конкретной проблеме.

Мэтью Флинн
источник
0

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

Джеймс
источник
2
Хотя в целом я с вами согласен , на самом деле это не тот ответ, который решает проблему ОП. «Не делай этого» - это ответ, но довольно плохой, если он не дает жизнеспособной альтернативы.
Яннис
@YannisRizos И хотя я с тобой тоже согласен , я все же думаю, что он дал здравый совет (или понимание, если совет не то слово). По этой причине +1. Хотя да, технически это не очень полезный ответ.
куплено777
-1

Давайте приступим к медным гвоздям. Нет абсолютно никакой необходимости в каком-либо игровом интерфейсе, шаблонах проектирования, абстрактных классах и UML.

Если у вас есть достаточное количество классов поддержки, таких как пользовательский интерфейс, моделирование и т. Д., То в основном весь ваш код, не относящийся к игровой логике, все равно используется повторно. Более того, ваш пользователь не меняет свою игру динамически. Вы не переворачиваете на 30 Гц между играми. Вы играете в одну игру около получаса. Таким образом, ваш «динамический» полиморфизм на самом деле совсем не динамический. Это довольно статично.

Таким образом, разумный способ пойти сюда - это использовать универсальную функциональную абстракцию, такую ​​как C # Actionили C ++ std::function, создать один класс Mancala, один Wari и один Kalah и перейти оттуда.

std::unordered_map<std::string, std::function<void()>> games = {
    { "Kalah", [] { return Kalah(); } },
    { "Mancala", [] { return Mancala(); } },
    { "Wari", [] { return Wari(); } }
};
void play() {
    std::function<void()> f;
    f = games[GetChoiceFromUI()];
    f();
    if (PlayAgain()) return play();
}
int main() {
    play();
}

Выполнено.

Вы не называете Игры. Игры зовут тебя.

DeadMG
источник
3
Я не понимаю, насколько это полезно. Человек, задающий этот вопрос, студент. Он явно спрашивает о принципах проектирования и взаимодействиях между двумя шаблонами проектирования. Утверждение, что в некоторых случаях в промышленности нет необходимости в шаблонах проектирования или UML, может быть правдой, но размышление о моделях проектирования, шаблонах проектирования и UML может быть темой вопроса, о котором нужно спросить.
Томас Оуэнс
3
О них нечего сказать, потому что они нигде не применяются. Нет смысла тратить ваше время на размышления о том, как бы вы полностью взялись за дизайн, используя шаблоны проектирования, если только вы не намерены сделать это уроком о том, как их не использовать.
DeadMG
4
В SoftDev наблюдается тревожная / раздражающая тенденция, когда используемые шаблоны проектирования считаются более важными, чем просто решение проблемы. Существует такая вещь, как чрезмерная инженерия.
Джеймс
2
@DeadMG: хотя вы оба в основном правы, в случае с OP проблема заключается в сдаче экзамена, и решение этой проблемы заключается в использовании шаблонов проектирования и UML. Неважно, насколько мы правы, если его профессор не согласен с его решениями, он не пройдет.
Горан Йович
2
Моя вся жизнь я всегда думал , что это был «латунь налог» ... Ничего себе, «медные гвозди» делает намного больше смысла. lol
купила777