函数式C# API设计(返回函数参数并增加计算结果)
有一个关于 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) 在此设计中,PrintCooperativesNew 仅获取一个参数。 2)奇怪的接口ILayoutedGraph诞生了,它不包含任何方法,只是 包装其他接口。 如果某个库有其他类型,如 INetwork、ITree,我们最终会得到 创建包装接口 ILayoutedNetwork、ILayoutedTree (这很糟糕)。
因此,这种技术仅在函数语言中使用,只是因为它们不能以其他方式工作(没有状态,因此函数必须将输入与计算信息结合起来以供外部例程使用),或者它在命令式世界中也可行?
非常感谢,
PS:可以在这里找到更详细、漂亮的打印示例 http://tivadj.blogspot.com/ 2009/02/designing-c-api-in-function-style.html
There is a question regarding usage of functional programming techiques in C# code. Example
Let we have interface
interface IGraph { /*contains vertices and edges*/}
Suppose we need to layout graph's vertices (assign Point to each vertex).
interface ILayoutInfo {
Point GetVertexPoint(vertex);
}
Simple layout route can have such signature:
ILayoutInfo SimpleLayout(IGraph graph);
Which can be used in such way
void Demo() {
IGraph graph = CreateGraphInAnyWay();
ILayoutInfo layout = SimpleLayout(graph);
PrintCoordinates(graph,layout);
}
In design below PrintCoordinates need both references to graph and layout.
Consider functional style design where layouting routing augments graph information
with information about graph vertices coordenates.
ILayoutedGraph SimpleLayoutNew(IGraph graph);
Where ILayoutedGraph implements BOTH IGraph and ILayoutInfo
void DemoNew() {
IGraph graph = CreateGraphInAnyWay();
ILayoutedGraph layoutedGraph = SimpleLayoutNew(graph);
PrintCoordinatesNew(layoutedGraph);
}
1)In this design PrintCoordinatesNew gets only ONE parameter.
2)Weird interface ILayoutedGraph was born which doesn't contain any methods and just
wraps other interfaces. If some library has other types like INetwork, ITree we end up
creating wrap interfaces ILayoutedNetwork, ILayoutedTree (which is bad).
So such techique is used only in functinal languages just because they can't work in other way (there are no state so function must combine input with calculated info to be used by outer routines) or it is viable in imperative world too?
Thanks a lot,
PS: a more verbose pretty printed example can be found here
http://tivadj.blogspot.com/2009/02/designing-c-api-in-functional-style.html
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
如果传递两个参数时让您感到不安的是您的布局(ILayoutInfo)链接到用于生成它的图形。 我传递带有未用于生成布局的图形的布局是没有意义的。
在这种情况下,您可以在布局信息中保留对图形的引用,并在 ILayoutInfo 接口上提供访问器。
这样,您只能传递 ILayoutInfo 实例,而您的 PrintCooperatives 函数仍然可以访问用于生成 ILayoutInfo 的图形。
如果您有其他类型的对象可以生成布局信息,请为它们使用通用接口,或使 ILayoutInfo 通用。
If seems that what disturbs you when passing two arguments is that your layout (ILayoutInfo) is linked to the graph used to generate it. I would be meaningless to pass a layout with a graph that was not used to generate it.
In this case, you can keep a reference to the graph in the layout info, and provide an accessor on the ILayoutInfo interface.
This way, you can only pass the ILayoutInfo instance, and you PrintCoordinates function can still acces the graph that was used to generate the ILayoutInfo.
If you have other kind of object that can generate layout infos, use a common interface for them, or make the ILayoutInfo generic.
您可以使用实现两个接口并将返回值转换为该类的类来实现此目的吗?
Can you implement this using a class that implements both interfaces and casting the returns as that class?
你原来的API没有问题,
功能完美。 命令式 API 在创建后会涉及到对
graph
的更改。 例如,对于 ILayoutedGraph、ILayoutedTree、ILayoutedQueue 等问题,我认为您可以通过函数式语言中的泛型类和 OO 语言中允许的多重继承来解决这个问题。
就我个人而言,我会推荐泛型:
ILayout
其中a
是需要布局的边缘的东西。There is no problem with your original API of
It is perfectly functional. An imperative API would involve a change to
graph
once it is created. EgAs for the problem of ILayoutedGraph, ILayoutedTree, ILayoutedQueue, etc, I think you would get around this by generic classes in a functional languages and multiple inheritance in the OO languages where this is allowed.
Personally, I would recommend generics:
ILayout<a>
wherea
is something with edges that needs to be laid out.