0

我正在研究图形实现。我的 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 类。当遍历图形时,我希望在算法当前遍历的边和顶点上调用一些代表。

我定义了 2 对代表,一对与必须在图形元素上执行的操作有关,例如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我正在尝试为and编写 BFS 版本EdgeDataOperation,当我意识到我最终应该复制所有 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 个委托传递给一个函数,但在每次遍历期间我只会使用其中的一对,所以它看起来不太干净。

4

1 回答 1

1

首先,我强烈建议您更改类型参数的命名。约定是使用T前缀,然后使用 PascalCased 名称,例如TVertexand TEdge

接下来,如果你发现自己想要几个相关的委托,那听起来你真的想要一个包含多个方法的接口。如果您想使用 lambda 表达式来表达操作,您始终可以创建接口的无操作实现以仅允许覆盖一个方法 - 甚至提供从委托创建具体实现的实例的静态方法。

这基本上就是 Reactive Extensions 对IObserver<T>界面所做的事情,而且效果很好。

于 2012-11-12T17:20:38.213 回答