2013-03-02 57 views
0

我在运行时使用Strategy Pattern和Abstract Factory Pattern在Calculator类中生成不同的算法。如何将基于泛型迭代器的算法与基于实现的算法结合起来?

计算将取决于相关类型之间的关系。这就是为什么我将“*算法::计算”作为成员函数模板的原因,对于关系来说是通用的。

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

基于实现的算法使用计算中涉及的类型的成员函数来完成计算。在这个例子中,它将使用RelationshipWithA :: target_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说:“从不重新定义继承的非虚函数”。我的意思是,非虚函数是实现不变的,它们不应该被一般覆盖,但是:

  1. 在C++中没有可用的虚拟成员函数模板。
  2. 如果我在RelationshipWithA和“*算法::计算”上创建一个vritual成员函数的算法类泛型,Factory需要知道Realtionship以生成算法,并且代码严重臭(至少对我而言)。

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

对于客户来说,行为之间并没有什么不同:结果在那里,唯一的区别在于它的计算方式。这意味着Is-A关系仍然保持:“*算法::计算”对于客户端来说仍然是实现不变的。

+0

什么是“基于实现的算法”? – 2013-03-02 13:09:47

+0

@CrisStringfellow,就像你在ImplementationBasedAlgorithm中看到的那样,它的实现不使用迭代器,它直接使用B成员函数:“B :: specific()”,这使得该算法只能与RelationshipWithA一起使用,该模板使用继承自B,例如C.但是,我希望算法也可以在不同的类型上工作(例如D),并且由于D不是从B继承的,所以ImplementationBasedAlgorithm将不会编译。实际上,A,B和D是来自不同库的非常复杂的类型(但相似),所以我使用通用算法保存代码。 – tmaric 2013-03-02 13:13:55

+0

@CrisStringFellow事实上,ImplementationBasedAlgorithm不能编译为D是*好*,这是我想要的,唯一的问题是我重写了非虚拟成员函数(模板),所以我需要知道这是否是生产守则的标准做法。 – tmaric 2013-03-02 13:15:34

回答

1

它不是一个真正的是-A关系......

,具体的实现是不是真的一个DefaultAlgorithm ...他们是特定的算法...

你可以有一个空的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类,并使计算()方法虚拟。
计算()方法会得到那么你可以的static_cast到具有要用于该算法的接口部分base_relationship接口的关系,所以你可以achive编译失败不具有正确的一个()类型()方法。

+0

我明白你的意思了,谢谢! :)但是,如何使关系成为完全两个单独的类类(B +继承类,D)的基类?我的意思是,在这种情况下派生的关系类之间没有什么共同之处,没有什么可以放在关系基类中。而关系本身是以一种通用的方式在关系中计算出来的。 – tmaric 2013-03-02 13:49:30

+0

你的目标是什么?你是否试图制作一个**列表 **,它将保存不同的算法? – 2013-03-02 14:09:59

+0

是的计算器有一套算法,但没有存储在容器(如列表)中,它们被定义为其成员函数。问题是算法是通用的。我想我会放弃工厂和运行时选择,并使用模板。这意味着重新编译单个客户端以实现相同算法的不同实现,这会在基准测试/测试期间造成一些痛苦,但是一旦我看到哪种算法效果最好,我会保持算法选择无论如何都是固定的。 – tmaric 2013-03-02 14:49:47