【问题标题】:Functional style C# API design (returning function parameter augmented with calculation result)函数式 C# API 设计(返回函数参数增加计算结果)
【发布时间】:2009-02-06 11:58:28
【问题描述】:

有一个关于在 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

【问题讨论】:

    标签: c# functional-programming method-chaining


    【解决方案1】:

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

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

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

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

    【讨论】:

    • 谢谢。你真的让我倒吸一口新鲜空气。
    【解决方案2】:

    您能否使用实现了接口并将返回转换为该类的类来实现这一点?

    【讨论】:

    • 问题是要发布什么API(接口):traitional style case1) IGraph, ILayoutInfo and SimpleLayout(IGraph):ILayoutInfo or functional style case2) IGraph, ILayoutedGraph SimpleLayoutNew(IGraph):ILayoutedGraph === = ILayoutedGraph 确实可以通过一些内部类来实现。
    【解决方案3】:

    你原来的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 是需要布置边缘的东西。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-09-15
      • 2015-09-28
      • 1970-01-01
      • 2022-12-06
      • 1970-01-01
      • 2012-12-27
      • 2016-02-12
      • 1970-01-01
      相关资源
      最近更新 更多