В настоящее время я создаю библиотеку, которая позволяет моделировать разнообразные игры меньшинств. Это предполагает, что агенты выбирают между двумя вариантами, скажем, A и B, поэтому основная функциональность агента заключается в выборе. Агент выигрывает очко за ход в игре, если он попадает в группу меньшинства после того, как все агенты выбрали.
Очевидно, что агент может сделать свой выбор бесконечно, и в игре исследуется влияние различных тактик выбора на общее состояние системы. Вот некоторые способы, с помощью которых мне нужно выбирать агентов:
- совершенно случайно
- получая память, чтобы они могли помнить прошлые выборы m меньшинства, используя эту память в качестве входных данных в отображении стратегии для прогноза выбора меньшинства
- , сделав прогноз и опубликовав его ряду других агентов, которые являются «друзьями» этого агента, а затем каждый агент выбирает, основываясь на каком-то условии, доверяет ли он своим друзьям.
Теперь о проблеме программирования. В настоящее время у меня есть абстрактный агент, который инкапсулирует все эти функции. Дело в том, что некоторые типы агентов не имеют списка друзей, набора стратегий, памяти и т. Д. В настоящее время все эти способности забивают базовый класс. Я мог бы использовать иерархию наследования, но я думаю, что в иерархии будет происходить перекрестный переход между разными классами, т. Е. Иногда у агента могут быть друзья и стратегии, а иногда просто друзья или стратегии. Точно так же у меня может быть коллекция интерфейсов, и каждый отдельный агент реализует все необходимые интерфейсы, т. Е.
public enum Choice {
A, B
}
public interface Decidable {
private Choice choice;
public Choice getChoice();
public void choose();
}
public interface Strategic {
private StrategyManager strategies;
public StrategyManager getStrategyManager;
public void setStrategyManager(StrategyManager strategyManager);
}
public class CleverAgent implements Decidable, Strategic {
// decides more intelligently using the strategies
}
public class StupidAgent implements Decidable{
public void choose() {
if(Math.random < 0.5) {
return Choice.A
} else {
return Choice.B
}
}
}
Теперь, если я пойду по этому маршруту, я уже смогу увидеть многочисленные интерфейсы, такие как Стратегический, Разложимый, Доступный, Сохраняющий состояние, Запоминающийся и Подходящий. Я чувствую, что реальное решение должно быть сочетанием иерархии наследования (я знаю, по крайней мере, что все агенты разрешимы, так что они должны входить в базовый класс) пары с подключаемым поведением.
Мой вопрос: каков наилучший подход в этом случае? Есть ли какие-то шаблоны дизайна, которые я должен изучить? Каковы преимущества и недостатки каждого подхода, особенно с точки зрения того, как он влияет на другой код в библиотеке, поскольку состояние агента необходимо исследовать на протяжении всей игры для экспериментов?
Любая помощь будет принята с благодарностью.