我正在进行图表实施。 My Graph类看起来像这样:
public class Graph<VERTEX_TYPE, EDGE_TYPE, IDENTIFIER_TYPE>
where VERTEX_TYPE : Identifier<IDENTIFIER_TYPE>
where EDGE_TYPE : Identifier<IDENTIFIER_TYPE>
where IDENTIFIER_TYPE : IConvertible
{
...
}
(请不要关心已实施的界面,它们与问题无关)。
Vertex和Edge类都包含一些可以通过这种方式访问的通用数据:
public class Vertex<VERTEX_TYPE,EDGE_TYPE,IDENTIFIER_TYPE>
where VERTEX_TYPE : Identifier<IDENTIFIER_TYPE>
where EDGE_TYPE : Identifier<IDENTIFIER_TYPE>
{
public VERTEX_TYPE Data{get;private set;}
....
}
public class Edge<EDGE_TYPE,VERTEX_TYPE,IDENTIFIER_TYPE>
where EDGE_TYPE : Identifier<IDENTIFIER_TYPE>
where VERTEX_TYPE : Identifier<IDENTIFIER_TYPE>
{
public EDGE_TYPE Data{get;private set;}
....
}
现在我有一个实现一些算法的GraphVisitor类。遍历Graph时,我希望在算法遍历的两个边和顶点上调用一些委托。
我定义了两对委托,一对与必须在图元素上执行的操作相关,例如Vertex<VERTEX_TYPE,EDGE_TYPE,IDENTIFIER_TYPE>
。
第二对代表与仅对数据持有的操作有关。
public class GraphVisitor<VERTEX_TYPE, EDGE_TYPE, IDENTIFIER_TYPE>
where VERTEX_TYPE : Identifier<IDENTIFIER_TYPE>
where EDGE_TYPE : Identifier<IDENTIFIER_TYPE>
where IDENTIFIER_TYPE : IConvertible
{
public delegate void VertexDataOperation(VERTEX_TYPE vertex);
public delegate void EdgeDataOperation(EDGE_TYPE vertex);
public delegate void VertexOperation(Vertex<VERTEX_TYPE,EDGE_TYPE,IDENTIFIER_TYPE> vertex);
public delegate void EdgeOperation(Edge<EDGE_TYPE,VERTEX_TYPE,IDENTIFIER_TYPE> vertex);
.....
}
我已经实现了BFS算法(我避免发布整个实现),将两个委托作为参数:
public void BFS(VertexOperation op, EdgeOperation edgeOp)
{
...
Vertex<VERTEX_TYPE,EDGE_TYPE,IDENTIFIER_TYPE> currentVertex;
op(currentVertex);
foreach (Edge<EDGE_TYPE,VERTEX_TYPE,IDENTIFIER_TYPE> e in currentVertex.NeighBors())
{
edgeOp(e);
...
}
...
我正在尝试为VertexDataOperation
和EdgeDataOperation
编写BFS版本,当我意识到我最终应该复制我的所有BFS代码以便使用2个不同的委托参数类型:
public void BFS(VertexDataOperation op, EdgeDataOperation edgeOp)
...
Vertex<VERTEX_TYPE,EDGE_TYPE,IDENTIFIER_TYPE> currentVertex;
op(currentVertex.Data); //method differs only here
foreach (Edge<EDGE_TYPE,VERTEX_TYPE,IDENTIFIER_TYPE> e in currentVertex.NeighBors())
{
edgeOp(e.Data);//method differs only here
...
}
我想避免使用相同方法的相同实现。唯一改变的是方法签名和调用方法的对象。
有没有人有任何想法来改进此代码的设计?
编辑:
我可以将所有4个代表传递给一个函数,但是我在每次遍历时只使用它们中的一对,所以它看起来不太干净。
答案 0 :(得分:1)
首先,我强烈建议您更改类型参数的命名。惯例是使用T
前缀,然后使用PascalCased名称,例如TVertex
和TEdge
。
接下来,如果您发现自己想要几个相关的委托,那听起来您真的想要一个具有多种方法的界面。您始终可以创建接口的无操作实现,以允许仅覆盖一个方法 - 或者甚至提供静态方法,如果要使用lambda表达式来表达操作,则可以从委托创建具体实现的实例。 / p>
这基本上是Reactive Extensions对IObserver<T>
界面的作用,而且效果非常好。