1

有一个关于在 C# 代码中使用函数式编程技术的问题。例子

让我们有接口

interface IGraph { /*contains vertices and edges*/}

假设我们需要布局图的顶点(将 Point 分配给每个顶点)。

interface ILayoutInfo {
  Point GetVertexPoint(vertex);
}

简单的布局路线可以有这样的签名:

ILayoutInfo SimpleLayout(IGraph graph);

哪个可以这样使用

void Demo() {
  IGraph graph = CreateGraphInAnyWay();
  ILayoutInfo layout = SimpleLayout(graph);
  PrintCoordinates(graph,layout);
}

在下面的设计中 PrintCoordinates 需要对图形和布局的引用。

考虑功能样式设计,其中布局路由通过有关图形顶点坐标的信息来增强图形信息。

ILayoutedGraph SimpleLayoutNew(IGraph graph);

ILayoutedGraph 实现 IGraph 和 ILayoutInfo 的地方

void DemoNew() {
  IGraph graph = CreateGraphInAnyWay();
  ILayoutedGraph layoutedGraph = SimpleLayoutNew(graph);
  PrintCoordinatesNew(layoutedGraph);
}

1)在这个设计中 PrintCoordinatesNew 只得到一个参数。2)奇怪的接口ILayoutedGraph诞生了,它不包含任何方法,只是包装了其他接口。如果某些库具有其他类型,例如 INetwork、ITree,我们最终会创建包装接口 ILayoutedNetwork、ILayoutedTree(这很糟糕)。

所以这种技术只用于函数式语言,只是因为它们不能以其他方式工作(没有状态,所以函数必须将输入与计算信息结合起来供外部例程使用),或者它在命令式世界中也是可行的?

非常感谢,

PS:可以在这里找到更详细的漂亮打印示例 http://tivadj.blogspot.com/2009/02/designing-c-api-in-functional-style.html

4

3 回答 3

0

您可以使用实现接口并将返回转换为该类的类来实现这一点吗?

于 2009-02-06T12:07:57.690 回答
0

你原来的API没有问题

void Demo() {
  IGraph graph = CreateGraphInAnyWay();
  ILayoutInfo layout = SimpleLayout(graph);
  PrintCoordinates(graph,layout);
}

它功能齐全。命令式 API 在创建后将涉及更改graph。例如

void Demo() {
  IGraph graph = CreateGraphInAnyWay();
  graph.Layout(new SimpleLayout()); // changes the state of graph
  PrintCoordinates(graph);
}

至于 ILayoutedGraph、ILayoutedTree、ILayoutedQueue 等问题,我认为您可以通过函数式语言中的泛型类和允许这样做的 OO 语言中的多重继承来解决这个问题。

就个人而言,我会推荐泛型:需要布置边缘的东西ILayout<a>在哪里。a

于 2009-02-07T01:20:28.713 回答
0

如果似乎在传递两个参数时打扰您的是您的布局(ILayoutInfo)链接到用于生成它的图形。传递带有不用于生成它的图形的布局是没有意义的。

在这种情况下,您可以在布局信息中保留对图形的引用,并在 ILayoutInfo 接口上提供访问器。

这样,您只能传递 ILayoutInfo 实例,而您的 PrintCoordinates 函数仍然可以访问用于生成 ILayoutInfo 的图形。

如果您有其他类型的对象可以生成布局信息,请为它们使用通用接口,或使 ILayoutInfo 通用。

于 2009-02-07T01:40:57.347 回答