Pattern Design Pattern - выбор между стратегиями со счетчиками - PullRequest
11 голосов
/ 07 июля 2011

Я программирую на Java, но это больше вопрос дизайна, поэтому любой программист на OO, вероятно, мог бы ответить на этот вопрос.У меня есть вопрос относительно шаблона проектирования стратегии.Вот несколько чернил, которые я нашел полезными:

Объясненный паттерн стратегии - ОО .

Я использую паттерн стратегии дважды с одной группой из четырех стратегий и одной группой из трех.В каждом случае я решаю, какую стратегию использовать, поддерживая счетчик с гниением.если стратегия, которую программное обеспечение решает использовать, успешна, то счетчик увеличивается на единицу.Если используемая стратегия не удалась, то счетчик уменьшается на единицу.Независимо от успеха или неудачи ВСЕ счетчики умножаются на число около 0,9, чтобы «затухать» счетчики с течением времени.Программное обеспечение будет выбирать, какую стратегию использовать, исходя из того, какая стратегия имеет самый высокий счетчик.Пример моего очень простого UML показан ниже:

Example UML.

И в виде ссылки (для удобства чтения): Пример UML

UML выше - это макет, который я хотел бы использовать.Если вы не можете сказать из вышеизложенного UML, я пишу игру «Камень, бумага, ножницы» с намерением обыграть всех моих друзей.

Теперь перейдем к проблеме:

Я не могу решить, как реализовать «систему счетчиков» для решения, какую стратегию использовать.Я думал о каком-то классе «данных», в котором можно хранить все счетчики и строки истории, но мне это показалось неуклюжим.Я всегда поддерживаю около 2 строк и около восьми счетчиков (может быть, больше, а может и меньше).Вот почему я думал о классе «данных», где можно хранить все.Я мог бы просто создать экземпляр класса, который будет использоваться в методах chooseStrategy () и chooseMetaStrategy (), но я просто не знаю.Это мой первый проект, над которым я буду работать самостоятельно, и я просто не могу ничего решить.Я чувствую, что есть определенно лучшее решение, но я не достаточно опытен, чтобы знать.

Спасибо!

------------------------------------продолжение 1 --------------------------------------------

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

Я искал совет Пола Сонье об использовании составного шаблона, и он выглядел очень интересно (спасибо, Пол!).Для целей HistoryMatching и «интеллектуальных» стратегий AntiRotation я хочу реализовать цепочку всех игр противника, доступных для обоих классов.Кроме того, я хочу, чтобы строка истории редактировалась независимо от того, какую стратегию сыграла моя программа, чтобы я мог вести точный учет игр противника.Чем полнее строка (на самом деле я, вероятно, буду использовать LinkedList, но если кто-нибудь знает о лучшем (подстроке / подсписке) методе поиска / подбора, пожалуйста, дайте мне знать), тем лучше стратегия может предсказать поведение противника.

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

Кроме того, TheCapn подчеркнул, что было бы неплохо хранить различные счетчики и историюколлекции для каждого противника.Любая мысль о том, как реализовать это с помощью составного шаблона?

Ответы [ 3 ]

6 голосов
/ 07 июля 2011

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

Это дает вам локальность (счет сохраняется в стратегииэто подсчет) и функциональная композиция (функциональность счета инкапсулирована в классе композиции).Кроме того, он поддерживает изоляцию класса стратегии от других влияний.

Ваша структура дизайна пока выглядит хорошо;Вы, безусловно, на хорошем и интересном пути.Надеюсь, это поможет!

3 голосов
/ 07 июля 2011

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

List<Strategy> strategies;
Strategy successfulStrategy = null;
for (Strategy strategy: strategies) {
    boolean success = strategy.attempt();
    if (success) {
        break;
        successfulStrategy = strategy;
    }
}
if (successfulStrategy == null) throw new NoSuccessfulStrategyException();
// now move the successful strategy to the front of the list
strategies.remove(successfulStrategy);
strategies.add(0, successfulStrategy);

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

Тем не менее, если вы не можете установить счет, то я бы создал Decorator , который оборачивает стратегию и ведет счет и который можно сравнить с другими такими объектами. Код - самое простое объяснение:

public class ScoredStrategy implements Strategy, Comparable<ScoredStrategy> {
    private final Strategy delegate;
    private float score;

    public ScoredStrategy(Strategy delegate) {
        this.delegate = delegate;
    }

    public boolean attempt() {
        boolean success = delegate.attempt();
        score = (score * 0.9f) + (success ? 1 : -1);
        return success;
    }

    public int compareTo(ScoredStrategy that) {
        return -Float.compare(this.score, that.score);
    }
}

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

1 голос
/ 07 июля 2011

Хотя "неуклюжий", я думаю, ваша интуиция верна.Сохраните все data в collection, к которому может получить доступ стратегия, которую вы решите реализовать.Сохраняйте отдельные data объекты для каждого из ваших оппонентов и создавайте новые data объекты, когда вы определяете новых противников, сохраняя их в коллекции, такой как Map, обеспечит легкий доступ.

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

Единственное другое логическое решение (из моего краткого мозгового штурма) состоит в том, чтобы лучше определитьокружающая логика или эвристика, которую вы планируете реализовать.Если вы создадите более конкретный способ выбора MetaStrategy, у вас будет лучшее понимание того, как данные должны быть собраны для доступа.Метод Тома Андерсона выглядит многообещающе для вашего проекта!

...