如何将基于泛型迭代器的算法与基于实现的算法结合起来?

How can I combine generic iterator-based algorithms with implementation based algorithms?

本文关键字:算法 实现 于实现 结合 起来 泛型 迭代器 于泛型      更新时间:2023-10-16

我在运行时使用策略模式和抽象工厂模式在计算器类中生成不同的算法。

计算将取决于所涉及类型之间的关系。这就是为什么我把"*Algorithm::calculate"作为一个成员函数模板,对于关系来说是通用的。

然而,我已经有了一个在现有代码中完全基于实现的算法,它不是泛型的,也不是基于迭代器的,我想将它添加到算法层次结构中,以便我也可以使用AbstractFactory生成它,并查看它的行为。

基于实现的算法使用计算中涉及的类型的成员函数来完成计算。在本例中,它将使用RelationshipWithA::target_type成员函数来访问type & &;的数据,并使用"A"成员函数来访问RelationshipWithA::a_.

这是我到目前为止想到的(这只是一个模型,没有抽象工厂和计算器类):

#include <iostream>
class Result{}; 
class A {};  
class B {
    public: 
        void specific() const 
        { 
            std::cout << "B::specific()" << std::endl;
        };
};
class C : public B {};
class D {};
template<class Type>
class RelationshipWithA
{
    const A& a_; 
    const Type& t_;
    public: 
        typedef Type target_type; 
        RelationshipWithA (const A& a, const Type& t)
            :
                a_(a), 
                t_(t)
        {
            std::cout << "RelationshipWithA::ctor" << std::endl;
        }; 
        const A& a() const 
        {
            return a_; 
        }
        const Type& type() const
        {
            return t_;
        }
};
class DefaultAlgorithm 
{
    public:
        template <class Relationship>
        void calculate (Result& res, const Relationship& r)
        {
            std::cout << "DefaultAlgorithm::calculate" << std::endl;
            const A& a = r.a(); 
            const typename Relationship::target_type& t = r.type(); 
            // Default iterator based calculation on a, target_type and r
        };
};
class AlternativeAlgorithm 
: 
    public DefaultAlgorithm 
{
    public:
        template <class Relationship>
        void calculate (Result& res, const Relationship& r)
        {
            std::cout << "AlternativeAlgorithm::calculate" << std::endl;
            // Optimized iterator based calculation on a, target_type and r
        }
};
class ImplementationBasedAlgorithm 
:
    public DefaultAlgorithm 
{
    public:
        // No specialization: Relationships store
        // a const reference to any class that inherits from B
        template <class Relationship>
        void calculate (Result& res, const Relationship& r)
        {
            // Use B implementation and the Relationship With  A to compute the result
            std::cout << "ImplementationBasedAlgorithm::calculate" << std::endl;
            const A& a = r.a(); 
            const B& b = r.type();
            b.specific();
            // Implementation based on B implementation
        }
};
int main(int argc, const char *argv[])
{
    Result res; 
    A a; 
    C c; 
    RelationshipWithA<C> relationshipAC (a, c);
    DefaultAlgorithm defaultAlg; 
    AlternativeAlgorithm alternativeAlg;
    ImplementationBasedAlgorithm implementationAlg;
    defaultAlg.calculate(res, relationshipAC);
    alternativeAlg.calculate(res, relationshipAC);
    implementationAlg.calculate(res,relationshipAC);
    D d; 
    RelationshipWithA<D> relationshipAD (a, d);
    defaultAlg.calculate(res, relationshipAD);
    alternativeAlg.calculate(res, relationshipAD);
    // This fails, as expected
    //implementationAlg.calculate(res,relationshipAD);
    return 0;
}

我喜欢这种设计,因为算法不是泛型类,这使得泛型抽象工厂很容易在运行时生成它们。

然而,Effective c++中有第36条说:"永远不要重新定义继承的非虚函数"。我的意思是,非虚函数是实现不变的,它们通常不应该被重写,但是:

    c++中没有虚成员函数模板。
  1. 如果我在RelationshipWithA和"*Algorithm::calculate"一个虚拟成员函数上使算法类泛型,工厂需要知道关系才能生成算法,并且代码变得非常臭(至少对我来说)。

这是一个适当的解决方案的问题,即使我重写继承的非虚函数(函数模板)?

对于客户端来说,在行为上没有任何区别:结果是存在的,唯一的区别是计算它的方式。这意味着仍然支持is - a关系:"*Algorithm::calculate"对客户机来说仍然是实现不变的。

这不是一个真正的Is-A关系…

具体的实现并不是真的A default_algorithm …它们是特定的算法…

您可以使用工厂创建一个空的BaseAlgorithm类。但是,在使用模板函数之前,无论如何都需要将其强制转换为正确的类型。无论如何,这有点优于工厂模式,因为您没有使用接口。

在您的例子中,如果工厂创建了一个派生类,但返回基类,如果您使用该变量,它将调用基类方法:

DefaultAlgorithm algo = Factory.CreateImplementationBasedAlgorithm();
RelationshipWithA<D> relationshipAD (a, d);
algo.calculate(res, relationshipAD); //won't fail because the base class methods are used (because it isn't virtual)
为了解决这个问题,您可以创建一个基本的Relationship类,并使calculate()方法为虚方法。
calculate()方法将获得,然后您可以将关系静态转换为具有该算法所需接口的某个base_relationship接口,因此您可以实现由于没有正确的a()type()方法而导致编译失败。