Я пытаюсь запрограммировать генетический алгоритм для проекта, и мне трудно разделять разные функции. Я читал о разработке на основе политик, и это кажется решением проблемы, но я не совсем понимаю, как это реализовать.
У меня есть OptimizerHost, который наследуется от SelectionPolicy (чтобы определить, какие решения оцениваются) и FitnessPolicy (для определения пригодности любого данного решения). Проблема в том, что я не могу понять, как две политики могут взаимодействовать друг с другом. Основная часть алгоритма реализована в SelectionPolicy, но ему все еще нужно уметь проверять пригодность своих решений. Единственное, о чем я могу думать, — это реализовать алгоритм SelectionPolicy в самом OptimizerHost, чтобы он унаследовал то, что ему нужно, от FitnessPolicy. Но похоже, что в первую очередь упускается из виду использование политик. Я что-то неправильно понимаю?
Я не очень знаком с принципами проектирования на основе политик (извините), но когда я прочитал вашу проблему, я почувствовал, что вам нужно что-то вроде чисто виртуальных классов (в качестве интерфейсов), чтобы помочь вам в этом.
Дело в том, что вы не можете использовать что-то от другого, если это не объявлено ранее: это основное правило. Таким образом, вам нужно использовать и виртуальный интерфейс, чтобы сказать SelectPolicy, что у FitnessPolicy есть несколько членов, которые будут использоваться. Пожалуйста, следуйте примеру и измените его в соответствии с вашими потребностями.
Первое: создайте интерфейсы для SelectionPolicy и FitnessPolicy.
template <class T> class FitnessPolicyBase
{
public:
virtual int Fitness(T fitnessSet); // assuming you have implemented the required classes etc. here - return value can be different of course
...
} // write your other FitnessPolicy stuff here
template <class T> class SelectionPolicyBase
{
public:
virtual T Selector(FitnessPolicyBase<Solution> evaluator, Set<T> selectionSet); // assuming such a set exists here
...
} // write your other selectionpolicy interface here
Теперь, поскольку мы сделали эти классы чисто виртуальными (у них нет ничего, кроме виртуальных функций), мы не можем их использовать, а только наследуем от них. Именно это мы и сделаем: класс SelectionPolicy и класс FitnessPolicy будут наследоваться от них соответственно:
class SelectionPolicy: public SelectionPolicyBase<Solution> // say, our solutions are of Solution Type...
{
public:
virtual Solution Selector(FitnessPolicyBase<Solution> evaluator, Set<Solution> selectionSet); // return your selected item in this function
...
}
class FitnessPolicy : public FitnessPolicy Base<Solution> // say, our solutions are of SolutionSet Type...
{
public:
virtual int Fitness(Solution set); // return the fitness score here
...
}
Теперь наш алгоритм может работать с двумя типами параметров: SolutionSetBase и FitnessSetBase. Нам действительно нужны были типы xxxBase? На самом деле, если у нас есть открытые интерфейсы классов SolutionPolicy и FitnessPolicy, мы могли бы их использовать; но, используя этот способ, мы как бы отделяли «логику» от проблемы.
Теперь наш алгоритм политики выбора может принимать ссылки на классы политики и затем вызывать требуемую функцию. Обратите внимание, что классы политики могут также вызывать классы друг друга. Так что это действительная ситуация сейчас:
virtual Solution SelectionPolicy::Selector(FitnessPolicyBase<Solution> evaluator, Set<T> selectionSet)
{
int score = evaluator.Fitness(selectionSet[0]); //assuming an array type indexing here. Change accordingly to your implementation and comparisons etc.
}
Теперь, чтобы это работало, вы должны инициализировать объект FitnessPolicy и передать его этому селектору. Благодаря апскейтингу и виртуальным функциям он будет работать правильно.
Пожалуйста, прости меня, если я слишком усложнял вещи — я был довольно далек от C ++ (в последнее время работал над C #), поэтому мог ошибиться в синтаксисе, но логика должна быть в любом случае такой же.
Других решений пока нет …