我正在使用策略模式和抽象工厂模式在运行时期间在Calculator类中生成不同的算法。
计算将取决于所涉及类型之间的关系。这就是为什么我将“* Algorithm :: calculate”作为成员函数模板,关于关系的泛型。
但是,我已经有一个完全基于实现的算法在现有代码中,它不是通用的,也不是基于迭代器的,我想将它添加到算法层次结构中,以便我可以使用AbstractFactory生成它同时也看看它是如何表现的。
基于实现的算法使用计算中涉及的类型的成员函数来完成计算。在这个例子中,它将使用RelationshipWithA :: target_type成员函数来访问Type&的数据,以及“A”成员函数来访问RelationshipWithA :: a _的数据。
这是我到目前为止提出的(这只是一个模型,没有Abstract Factory和Calculator类):
#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;
}
我喜欢这种设计,因为算法不是泛型类,这使得Generic Abstract Factory可以在运行时轻松生成它们。
然而,在Effective C ++中有一个第36项说:“永远不会重新定义一个继承的非虚函数”。我的意思是,非虚函数是实现不变的,它们通常不应该被覆盖,但是:
这是否是解决问题的正确方法,即使我覆盖了继承的非虚函数(函数模板)?
对于客户来说,行为没有任何区别:结果是存在的,唯一的区别在于它的计算方式。这意味着仍然支持Is-A关系:“* Algorithm :: calculate”仍然是对客户端的实现不变。
答案 0 :(得分:1)
这不是一个 Is-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
类,并将 calculate()方法设为虚拟。
calculate()方法将获得静态广播关系到某个base_relationship接口,该接口具有您想要该算法的接口,因此您可以在没有正确的的情况下实现编译失败a()或 type()方法。