如何使用具有相似功能但签名不同的方法设计类

时间:2018-01-24 16:17:52

标签: c++ oop class-design

我手头的任务是编写一个系统来测试库中n个不同的算法 - 所有这些算法都执行相同的广泛任务但使用不同的方法。我想创建一个main类,我发送一个定义要使用的算法的参数。此main类依次调用传递要使用的参数的taskAlgorithm类以及要使用的算法所需的输入参数。然后taskAlgorithm类应该实例化要在其构造函数中使用的特定算法类。 taskAlgorithm::Process应运行算法并存储结果,taskAlgorithm::Result应返回结果。

我一直在想弄清楚如何写这个taskAlgorithm课程。在此类的构造函数中,基于algorithmCode参数,我想实例化特定算法的对象,但是,所有算法类都不同,并且不一定具有公共基类。解决这个问题的最佳方法是什么?

具体在

taskAlgorithm::taskAlgorithm(int algorithmCode, int argument1){
   if(algorithmCode == 1){
      //instantiate the algorithm1 object
   }
   else if(algorithmCode == 2){
      //instantiate algorithm2 object
   }
}

如果它们不一定共享一个公共基类,我应该如何为每个不同的算法类实例化对象?

2 个答案:

答案 0 :(得分:2)

如果它们是相关的算法,也许你可以想到"普通"如果你知道要使用哪些部分,或者要执行哪些转换,那么如果它存在,它将能够调用任何算法。

这将允许您为所有算法编写包装器接口,因此可以统一调用它们。每个包装器都可以知道"如何使用其输入来调用它包装的底层算法。我没有在这里做,但你可以为返回值做同样的事情。

例如,算法A是将一对迭代器转换为int的向量和比较器的排序,而算法B是一种不同类型的排序,带有指向int数组,长度和比较器的指针。

class Algo {
public:
    using Iter = std::vector<int>::iterator;
    using Compare = ...;
    virtual void call(Iter b, Iter e, Compare comp) = 0;
    virtual ~Algo() = default;
};

class A : public Algo {
    void call(Iter b, Iter e, Compare comp) override {
      algorithmA(b, e, comp);
    }
};

class B : public Algo {
    void call(Iter b, Iter e, Compare comp) override {
        if (b != e) {
            algorithmB(&*b, std::distance(b, e), comp);
        }
    }
};

现在你可以用A类包装算法A,用B类包装算法b,并且它们被相同地调用,并且包装器共享一个公共基类,因此可以多态地使用它们。

当然,您无法对虚函数进行模板化,因此迭代器类型是固定的,但此处的示例是关于创建一个包装器层次结构,以规范化算法的接口。然后你可以避免讨厌的switch语句(这需要在每次添加新算法时编辑工作代码。)使用类包装器方法,只需用新的包装器类包装新算法,它应该适合任何已经使用的系统现有算法(假设您不改变虚拟调用()函数的签名)。

这并没有完全回答你的问题,但我认为它足够接近可能有用。 :)

答案 1 :(得分:1)

根据问题的评论,我认为在这种情况下,这是唯一合理的方法:

// structure of all possible arguments to all your algorithms
struct AlgorithmArgs {
    int arg1;
    int arg2;  // etc ...
}

class AlgorithmWrapper {
public:
    AlgorithmWrapper(int algorithmId, const AlgorithmArgs args) {
        if (algorithmId == 1) {
            algorithm_ = Algorithm1{};  // or whatever you do to construct that Algorithm1 object
        } else if ( /* etc ... */ ) {}
    }

    void someMethodToUnifyAllAlgorithmInterfaces1();
    void someMethodToUnifyAllAlgorithmInterfaces2();
    void someMethodToUnifyAllAlgorithmInterfaces3();

private:
    std::variant<Algorithm1, Algorithm2, Algorithm3> algorithm_;
};

taskAlgorithm::taskAlgorithm(int algorithmCode, int argument1){
    AlgorithmArgs args;
    args.arg1 = argument1;
    algorithmWrapperPtr_ = new AlgorithmWrapper(algorithmCode, args);

    executeSomeUnifiedProcedureCommonForAllAlgorithms();
}