是否允许复制粘贴编程?

时间:2016-03-05 00:22:48

标签: c++ coding-style

我有一个名为GeneticOperator的班级,负责遗传程序中的突变和交叉算子。我有不同的突变函数和一个突变的公共函数,其中我有类型的switch语句。在函数random()中,我研究突变类型和染色体中突变的基因数量。

class GeneticOperator
{
public:
    enum MutationType
    {
        FUNCTION_MUTATION,
        ARGUMENTS_MUTATION,
        WORSTGENES_MUTATION //not implemented yet
    };
    enum CrossoverType //not implemented yet
    {
        ONEPOINT_CROSSOVER,
        TWOPOINT_CROSSOVER,
        UNIFORM_CROSSOVER,
        BESTGENE_CROSSOVER
    };
public:
    GeneticOperator();
    //GeneticOperator(const GeneGenerator* geneGenerator,
    //                int maxNGene);


    ChromosomePtr mutation(const Chromosome& parent) const;

private:
    void random();

    ChromosomePtr functionMutation(const Chromosome& parent) const;
    ChromosomePtr argumentsMutation(const Chromosome& parent) const;
private:
    const GeneGenerator* geneGenerator_;
    MutationType mutationType_;
    CrossoverType crossoverType_;
    int nMutatedGene_;
    int maxNMutatedGene_;
};

功能:

ChromosomePtr GeneticOperator::mutation(const Chromosome &parent) const
{
    if (parent.getSize() < maxNMutatedGene_)
    {
        throw "Za malo genow w chromosomie";
    }
    this->random();
    switch(mutationType_)
    {
    case FUNCTION_MUTATION:
        return functionMutation(parent);

    case ARGUMENTS_MUTATION:
        return argumentsMutation(parent);

    case WORSTGENES_MUTATION:
        //not implemented yet
        break;

    default:
        throw "Bad enum type";
        break;
    }
    return nullptr;
}

ChromosomePtr GeneticOperator::functionMutation(const Chromosome &parent) const
{
    ChromosomePtr child = parent.copy();

    for(int i = 0; i < nMutatedGene_; i++)
    {
        GenePtr newGene = nullptr;
        int geneNumber = rand() % (parent.getSize() - 1);

        switch(parent.getGene(geneNumber)->getType())
        {
        case Gene::TERMINAL_GENE:
            i--;
            break;

        case Gene::FUNCTION_GENE:
            int nArguments = parent.getGene(geneNumber)->getNArguments();
            GenePtr randomGene = move(geneGenerator_->getRandomFunctionGene(nArguments));
            for(int k = 0; k < nArguments; k++)
            {
                randomGene->addChild(parent.getGene(geneNumber)->getChild(k));
            }
            break;
        }
    }

    return child;
}

ChromosomePtr GeneticOperator::argumentsMutation(const Chromosome& parent) const
{
    ChromosomePtr child = parent.copy();

    for(int i = 0; i < nMutatedGene_; i++)
    {
        GenePtr newGene = nullptr;
        int geneNumber = rand() % (parent.getSize() - 1);

        switch(parent.getGene(geneNumber)->getType())
        {
        case Gene::TERMINAL_GENE:
            i--;
            break;

        case Gene::FUNCTION_GENE:
            GenePtr randomGene = move(parent.getGene(geneNumber)->clone());
            int nArguments = parent.getGene(geneNumber)->getNArguments();
            for(int k = 0; k < nArguments; k++)
            {
                int childGeneNumber = rand() % geneNumber;
                randomGene->setChild(childGeneNumber, k);
            }
            break;
        }
    }

    return child;
}

functionMutation()argumentsMutation()看起来像复制粘贴编程。

我该如何避免它?我尝试在此函数中仅返回GenePtr,但方法mutation()尚未清除。

你会建议什么?

3 个答案:

答案 0 :(得分:2)

复制粘贴的方法实际上只是混杂着不必要的代码。我摆脱重复的解决方案是添加一个从父基因中获取随机函数基因的函数。这也将澄清这些功能的目的。

GenePtr GeneticOperator::getRandomFuncGene(const Chromosome &parent) const
{
    while(true)
    {
        int geneNumber = rand() % (parent.getSize() - 1);
        if (parent.getGene(geneNumber)->getType()) 
        {
            return parent.getGene(geneNumber);
        }
    }
}

使用新方法并在删除杂乱之后,旧函数如下所示:

ChromosomePtr GeneticOperator::functionMutation(const Chromosome &parent) const
{
    for(int i = 0; i < nMutatedGene_; i++)
    {
        GenePtr funcGene = getRandomFuncGene(parent);

        int nArguments = funcGene->getNArguments();
        GenePtr randomGene = move(geneGenerator_->getRandomFunctionGene(nArguments));
        for(int k = 0; k < nArguments; k++)
        {
            randomGene->addChild(funcGene->getChild(k));
        }
    }

    return parent.copy();
}

ChromosomePtr GeneticOperator::argumentsMutation(const Chromosome& parent) const
{
    for(int i = 0; i < nMutatedGene_; i++)
    {
        GenePtr funcGene = getRandomFuncGene(parent);

        GenePtr randomGene = move(funcGene->clone());
        int nArguments = funcGene->getNArguments();
        for(int k = 0; k < nArguments; k++)
        {
            int childGeneNumber = rand() % geneNumber;
            randomGene->setChild(childGeneNumber, k);
        }
    }

    return parent.copy();
}

我希望我没有误解代码,但很难猜出有时会发生什么。

这些功能还存在一些其他问题。据我所知,返回值与函数的实际目的不符。

答案 1 :(得分:1)

关于你的问题标题

  

有时允许复制粘贴编程吗?

没有。这是从骨头上错误的 1 (嘿,押韵)。

  

我该如何避免呢?

避免复制/粘贴实现的常用方法是提供模板函数或类,以分解非特定类型的代码。

可以重构类型特定代码以键入专门的函数调用。

1)甚至还通过静态代码分析工具进行了大量工作来检测复制/复制修改后的代码,并警告可能存在的错误。 用最少误报来检测这个的真正好的工具非常昂贵,所以就这样做吧。

答案 2 :(得分:-2)

ChromosomePtr GeneticOperator::mutation(const Chromosome &parent, string type) const
{

    ChromosomePtr child = parent.copy();

    for(int i = 0; i < nMutatedGene_; i++)
    {
        GenePtr newGene = nullptr;
        int geneNumber = rand() % (parent.getSize() - 1);

        switch(parent.getGene(geneNumber)->getType())
        {
        case Gene::TERMINAL_GENE:
            i--;
            break;

        case Gene::FUNCTION_GENE:
            if(type == "function"){
                functionM(parent);
            }else if(type == "argument"){
                argumentM(parent);
            }
            break;
        }
    }

    return child;
}