Я занимаюсь разработкой структуры генетического алгоритма и первоначально принял решение о следующем IIndividual
определении:
public interface IIndividual : ICloneable
{
int NumberOfGenes { get; }
double Fitness { get; }
IGene GetGeneAt(int index);
void AddGene(IGene gene);
void SetGeneAt(int index, IGene gene);
void Mutate();
IIndividual CrossOverWith(IIndividual individual);
void CalculateFitness();
string ToString();
}
Все выглядело хорошо, но как только я разработал другие классы, которые использовали IIndividual
, я пришел к выводу, что создание юнит-тестов для этих классов было бы довольно болезненно. Чтобы понять почему, я покажу вам график зависимости IIndividual
:
Таким образом, при использовании IIndividual
мне приходится также создавать / управлять экземплярами IGene
и IInterval
.
Я могу легко решить эту проблему, переопределив мой IIndividual
интерфейс следующим образом:
public interface IIndividual : ICloneable
{
int NumberOfGenes { get; }
void AddGene(double value, double minValue, double maxValue);
void SetGeneAt(int index, double value);
double GetGeneMinimumValue(int index);
double GetGeneMaximumValue(int index);
double Fitness { get; }
double GetGeneAt(int index);
void Mutate();
IIndividual CrossOverWith(IIndividual individual);
void CalculateFitness();
string ToString();
}
со следующим графом зависимостей:
Это будет довольно легко протестировать, за счет некоторого снижения производительности (меня сейчас это не очень беспокоит) и увеличения веса на IIndividual
(больше методов). Существует также большая проблема для клиентов IIndividual, так как, если они хотят добавить Джин, им нужно будет добавить все маленькие параметры Джина «вручную» в AddGene(value, minimumValue, maximumValue)
вместо AddGene(gene)
!
Мой вопрос:
Какой дизайн вы предпочитаете и почему? Кроме того, по каким критериям знать, где остановиться?
Я мог бы сделать то же самое, что и с IIndividual
до IGene
, поэтому любой, кто использует IGene
, не должен знать о Interval
.
У меня есть класс Population
, который будет служить коллекцией IIndividuals
. Что мешает мне сделать то же самое, что я сделал с IIndividual
до Population
? Должна быть какая-то граница, какие-то критерии, чтобы понять, в каких случаях лучше всего просто оставить это (иметь некоторые зависимости), а в каких случаях лучше их скрывать (как во второй реализации IIndividual
).
Кроме того, при реализации фреймворка, который должен использоваться другими людьми, я чувствую, что второй дизайн менее симпатичен (и, возможно, другим труднее его понять).
Спасибо!