声明:此答案不适用于F#。马克的答案是最好的F#提供。特别是有区别的联合方法,C#没有直接的等价物。
但你问“功能”,和其他一些功能语言有更好的选择。其他功能语言,如Scala和Haskell提供了一个名为typeclasses的特性,它基本上可以使扩展方法实现一个接口,然后在事实之后再使用该接口。
那么这是如何相关?那么用F#你必须要么A)预先确定你在判别联盟中的所有案例,要么B)在你的数据库中放置渲染功能。两者都不是理想的。
随着类型类,你可以单独定义的记录类型:
// Blog.fs
type Blog {...}
[<SomeProviderAttribute>]let getBlogs() = ... // returns Blog seq
// Movie.fs
type Movie = {...}
[<SomeProviderAttribute>]let getMovies() = ... // returns Movie seq
然后,你可以在更高层次上的接口箭:(伪代码如下)
// UiBase.fs
class Renderable where render :: 'T -> string
// BlogUi.fs
instance Renderable Blog where render blog = blog.header + blog.text
// MovieUi.fs
instance Renderable Movie where render movie = movie.title + movie.description
从主UI区域
最后收集渲染的字符串很容易。如果您打开定义类型类的模块,你可以互换使用它们:
// MainUi.fs
open Blog; open Movie; open UiBase; open BlogUi; open MovieUi
// Just like you'd have to call "using" in C# to get the extention methods,
// you have to open these to get the type classes
let dataProviders = ... // Some assembly search and reflection here;
// say it returns [getBlogs; getMovies]
// (and note without the common typeclass,
// those two would be incompatible)
let renderedStrings =
seq { for provider in dataProviders do
for renderable in provider() do
yield render renderable }
所以基本上可以让你使用(否则完全无关)互换上级博客和电影类和供应商,是因为你能够“中断”中间层的界面。非常非常酷,适合你在这里遇到的常见问题。
...不幸的是F#本身没有这个功能。
@ user2864740一个接口只不过是一个荣耀的抽象类,根本没有任何实现。我的问题不在于如何实施我的API和它的运营合同。这是关于如何实现我的数据结构。 –
@ user2864740 - 我知道所有关于正确的OO设计原则。我在问适当的函数式编程设计原则。这是我的问题的目的。我不是在这里挑选一个类和一个接口之间的区别。我的观点是,使用继承,无论是类还是接口,都是我知道的唯一选择。在f#中,由于继承要求,使用标准的.NET类或接口排除了供应商使用歧视联合或记录类型的可能性。如果我没有弄错,在某些情况下也会消除类型推断 –
如果您对“帮助”非常认真*,请包括相关/建议结构。这个问题再一次不是与“纯粹功能性”相关的。 – user2864740