Первый, очевидный вариант - рассмотреть, должны ли члены Chromosome
быть или не быть public
.Учитывая, что вы хотите, чтобы произвольное число классов имело доступ к его данным, очевидным вариантом является сделать эти данные public
.
. Второй вариант для Chromosome
- предоставить общедоступный метод получения и установки длязатронутые данные, такие как;
class Chromosome
{
public:
std::vector<double> getGenes() const {return m_genes;};
bool setGenes(const std::vector<double> &newgenes)
{
bool is_error = true;
if (IsValid(newgnes))
{
is_error = false;
m_genes = newgenes;
}
return is_error; // return true if change is rejected
};
private:
std::vector<double> m_genes;
};
Тогда все, что нужно сделать CrossOverStrategy
и его производным классам, учитывая действительные указатели на Chromosome
s, это запросить гены, сделать все, что нужно, и (когда закончите) предоставьте новый набор генов обратно выбранному Chromosomes
.
Инкапсуляция Chromosome
сохраняется различными мерами, поскольку единственный способ изменить гены - через функцию-член Chromosome
, т.е.нет никакого способа изменить гены в хромосоме вне контроля класса Chromosome
.Что позволяет Chromosome
делать любые проверки, которые ему нравятся, и отвергать плохие гены, если это необходимо.
Нет необходимости в том, чтобы другой класс или функция были другом Chromosome
.Основным преимуществом является то, что нет необходимости изменять класс Chromosome
всякий раз, когда новый класс является производным от CrossOverStrategy
.
Компромисс состоит в том, что гены извлекаются и изменяются путем копирования полного набора (потенциальное снижение производительности при копировании).Но это избавляет от необходимости нарушать инкапсуляцию класса Chromosome
, предоставляя, прямо или косвенно, ссылку на его закрытые члены для любых других классов.
Если копирование полного набора хромосом плохо,разработать некоторые дополнительные функции-члены Chromosome
, которые позволяют вызывающей стороне запрашивать частичные изменения (например, обновлять определенные гены, вставлять набор генов в указанное место в векторе генов и т. д.).Эти дополнительные функции должны работать по тому же принципу: все изменения генов в Chromosome
проходят через функции-члены Chromosome
, и нет никакого механизма «задней двери», чтобы другой код мог пропустить изменения.
Если вы действительно хотите, вы можете сделать установщик и получатель private
членами Chromosome
и сделать только базовый класс CrossOverStrategy
a friend
.Тогда все, что нужно CrossOverStrategy
, - это предоставить protected
помощников, которые вызывают только частных помощников Chromosome
.
class CrossoverStrategy
{
public:
virtual std::vector<Chromosome*> crossover(Chromosome *parent1, Chromosome *parent2) = 0;
protected:
std::vector<double> getGenes(Chromosome *instance)
{
return instance ? instance->getGenes() : std::vector<double>();
};
bool setGenes(Chromosome *instance, const std::vector<double> &newgenes)
{
return instance ? instance->setGenes(newgenes)) : true; // true indicates error
};
};
Таким образом, только классы, полученные из CrossOverStrategy
, могут получить доступ к protected
помощники.Если работа Chromosome
изменится, то единственный класс, который необходимо адаптировать в этом случае, - это базовый класс CrossOverStrategy
- поскольку его производные классы (напрямую) вообще не обращаются к Chromosome
.