如何用功能相似但签名不同的方法设计class
How to design a class with methods which have similar functions but different signatures
我手头的任务是编写一个系统来测试库中的 n
不同算法 - 所有算法都执行相同的广泛任务,但使用不同的方法。我考虑过创建一个 main
class 并向其发送定义要使用的算法的参数。这个 main
class 又调用 taskAlgorithm
class 传递要使用的参数和要使用的算法所需的输入参数。然后 taskAlgorithm
class 应该实例化要在其构造函数中使用的特定算法 class。 taskAlgorithm::Process
应该 运行 算法并存储结果,taskAlgorithm::Result
应该 return 结果。
我一直在思考如何编写这个 taskAlgorithm
class。在这个class的构造函数中,基于algorithmCode
参数我想实例化一个具体算法的对象,但是,所有的算法class都是不同的,不一定有共同的基地 class。解决此问题的最佳方法是什么?
具体在
taskAlgorithm::taskAlgorithm(int algorithmCode, int argument1){
if(algorithmCode == 1){
//instantiate the algorithm1 object
}
else if(algorithmCode == 2){
//instantiate algorithm2 object
}
}
如果每个不同的算法 classes 不一定共享一个公共基础,我应该如何实例化对象 class?
根据问题下的评论,我认为在这种情况下这是唯一合理的做法:
// 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();
}
如果它们是相关算法,也许您可以想到 "common" 接口,如果它存在,如果您知道要使用哪些部分或哪些转换,则能够调用任何算法执行。
这将允许您为所有算法编写一个包装器接口,以便可以统一调用它们。每个包装器可以 "know" 如何获取其输入以调用它包装的底层算法。我没有在此处执行此操作,但您可以对 return 值执行相同的操作。
例如,算法 A 是一种将一对迭代器放入一个整数向量和一个比较器的排序,而算法 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);
}
}
};
现在你可以用 class A 包装算法 A,用 class B 包装算法 b,它们被相同地调用,并且包装器共享一个公共基础 class 所以它们可以多态使用。
当然,您不能将虚函数模板化,因此迭代器类型是固定的,但这里的示例是关于制作一个包装器层次结构来规范化算法的接口。然后你可以避免讨厌的 switch 语句(每次添加新算法时都需要编辑工作代码。)使用 class 包装器方法,只需用新包装器 class 包装新算法,它应该只是适用于任何已经使用现有算法的系统(前提是您不更改虚拟 call() 函数的签名)。
这并不能完全回答您的问题,但我认为它足够接近,可能会有用。 :)
我手头的任务是编写一个系统来测试库中的 n
不同算法 - 所有算法都执行相同的广泛任务,但使用不同的方法。我考虑过创建一个 main
class 并向其发送定义要使用的算法的参数。这个 main
class 又调用 taskAlgorithm
class 传递要使用的参数和要使用的算法所需的输入参数。然后 taskAlgorithm
class 应该实例化要在其构造函数中使用的特定算法 class。 taskAlgorithm::Process
应该 运行 算法并存储结果,taskAlgorithm::Result
应该 return 结果。
我一直在思考如何编写这个 taskAlgorithm
class。在这个class的构造函数中,基于algorithmCode
参数我想实例化一个具体算法的对象,但是,所有的算法class都是不同的,不一定有共同的基地 class。解决此问题的最佳方法是什么?
具体在
taskAlgorithm::taskAlgorithm(int algorithmCode, int argument1){
if(algorithmCode == 1){
//instantiate the algorithm1 object
}
else if(algorithmCode == 2){
//instantiate algorithm2 object
}
}
如果每个不同的算法 classes 不一定共享一个公共基础,我应该如何实例化对象 class?
根据问题下的评论,我认为在这种情况下这是唯一合理的做法:
// 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();
}
如果它们是相关算法,也许您可以想到 "common" 接口,如果它存在,如果您知道要使用哪些部分或哪些转换,则能够调用任何算法执行。
这将允许您为所有算法编写一个包装器接口,以便可以统一调用它们。每个包装器可以 "know" 如何获取其输入以调用它包装的底层算法。我没有在此处执行此操作,但您可以对 return 值执行相同的操作。
例如,算法 A 是一种将一对迭代器放入一个整数向量和一个比较器的排序,而算法 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);
}
}
};
现在你可以用 class A 包装算法 A,用 class B 包装算法 b,它们被相同地调用,并且包装器共享一个公共基础 class 所以它们可以多态使用。
当然,您不能将虚函数模板化,因此迭代器类型是固定的,但这里的示例是关于制作一个包装器层次结构来规范化算法的接口。然后你可以避免讨厌的 switch 语句(每次添加新算法时都需要编辑工作代码。)使用 class 包装器方法,只需用新包装器 class 包装新算法,它应该只是适用于任何已经使用现有算法的系统(前提是您不更改虚拟 call() 函数的签名)。
这并不能完全回答您的问题,但我认为它足够接近,可能会有用。 :)