问题
我想实现一些算法,这些算法在图上工作,并返回节点对的分数,以指示这些节点是否相似。算法应该在单个节点对和所有可能的节点对上工作。在后一种情况下,应返回集合/矩阵。
我的方法
算法源于
class SimilarityAlgorithm {
public:
Base(const Graph& G);
virtual double run(node u, node v) = 0; // indices for nodes in the graph
virtual ScoreCollection& runAll() = 0;
}
现在,算法在内存使用上有所不同。有些算法可能是对称的,并且(u,v)和(v,u)的分数是相同的这需要返回不同的ScoreCollection类型。一个例子是稀疏矩阵和一个三角形矩阵,它们都来自
ScoreCollection
。这可以归结为协变返回类型:
class SpecificAlgorithm : SimilarityAlgorithm {
public:
double run(node u, node v);
// The specific algorithm is symmetric and thus uses a symmetric matrix to save memory
SymmetricScoreCollection& runAll();
}
问题
这种设计方法是解决这个问题的好办法吗?
集合都作为矩阵实现的事实是否应该公开?
最佳答案
你的设计似乎适合你所描述的问题。
问题:
但是,SpecificAlgorithm
有一个问题:runAll()
没有返回与基类的虚函数相同的类型因此不会调用它(或者更可能的是,由于缺少虚拟函数,您的代码不会编译)。
解决方案:
通过使ScoreCollection
成为SymmetricScoreCollection
的派生类,还可以对ScoreCollection
使用多态方法:
class SymetricScoreCollection: public ScoreCollection {
//define the member functions to access the values virtual
...
};
class SpecificAlgorithm : public SimilarityAlgorithm {
public:
double run(node u, node v);
// The specific algorithm is symmetric and thus uses a symmetric matrix to save memory
ScoreCollection& runAll();
};
实际上,它是factory method pattern的一个应用程序,具有以下角色:
相似算法就是工厂,
具体算法是混凝土厂
ScoreCollection是产品
SymetricCoreCollection是具体产品
附加说明:
从
ScoreCollection
返回对runAll()
的引用会带来一些风险。假设sa
是一个特定的算法。在以下声明中:
ScoreCollection sc = sa.runAll();
sa.runAll()
返回对aSymetricScoreCollection
的引用,但它会将引用的对象复制到sc,使其成为scorecollection。Slicing发生,多态性将无法工作。但以下声明将获得成功:
ScoreCollection& rsc = sa.runAll();
因为rsc是一个引用,它仍然引用由
SymetricScoreCollection
返回的原始sa.runAll()
对象,并且一切都将按设计工作。你看,在返回引用时,很容易出现未注意到的错误。我建议返回一个指针而不是引用。