我正在学习Erlang,我正在尝试创建一个非常示例的博客程序。然而,我的思想目前被困在OO世界( var p = new Post(); p.Title =“”; p.Save(); )。我想了解Erlang中的一些基本思路。而不是在数据结构方面创建Post对象( p.Title,p.DateCreated,p.Body )?我应该使用元组吗?我想了解推荐的做这种事情的方法(特定于Erlang和/或特定于功能编程)。或者我在Erlang或FP中做的根本错误是什么?
要求(以OO术语,不确定如何用FP术语解释^ _ ^):
感谢。
更新: 我不是在寻找在Erlang中进行OOP的具体方法,除非它是推荐的方式。我正在寻找标准/推荐的方式来做问题中描述的内容,但我并不是想在Erlang中复制OOP。
答案 0 :(得分:6)
Erlang 是面向对象的语言。如果你像Alan Kay描述的那样看OOP,这个陈述就有了更大的力量:
OOP对我来说只意味着本地消息 保留,保护和隐藏 国家进程和极端 所有事情的后期约束。
正如您必须意识到的那样,Erlang提升了一种称为 Concurrency Oriented Programming 的编程风格,在这种编程风格中,您将对象抽象为通过消息传递进行通信的独立进程。每个进程都有它的本地状态,它们生活在自己的并行世界中。动态多态性是通过以下事实实现的:您可以定义可以响应消息的公共集的进程的类。由于Erlang'对象'生活在他们自己的微小过程中,它成为现实世界建模的自然媒介。您可以在Erlang中比任何其他语言更好地利用您的OOP技能。
无法在如此小的空间内完整描述Erlang中的OOP。我建议你阅读这本书Programming Erlang: Software for a Concurrent World。
另见这些链接:
答案 1 :(得分:5)
我会使用记录:
-record(post, {title, date_created, body, comments = []}).
-record(comment, {created_by, date_created, content}).
然后,如果你想使用mnesia作为数据库:
Post = #post{title = "", body = "", date_created = erlang:universaltime()},
mnesia:transaction(fun() -> mnesia:write(Post) end).
添加评论:
Comment = #comment{created_by = "", content = "", date_created = erlang:universaltime()},
mnesia:transaction(fun() ->
[Post] = mnesia:read(post, Title),
PostWithNewComment = Post#post{comments = [Comment | Post#post.comments]},
mnesia:write(PostWithNewComment)
end).
我没有测试过代码,但这就是我要做的。我还假设每个标题都是独一无二的。
答案 2 :(得分:0)
您的示例并不代表良好的OO风格。评论出现在已发布的博客文章中,因此到那时您只需要对评论发布到的帖子ID进行某种引用。
对于面向对象编程,拥有某种发送帖子和评论对象的BlogDb对象会更有意义。评论对象需要知道它是评论的帖子ID。您不应该使用'new'运算符创建post和comment对象,而是BlogDb接口具有返回这些对象的新实例的方法。
突然间你有一种可行的方法在Erlang中实现同样的东西。启动一个gen_server,即blog_db。做像
这样的事情Post = myblog:post(Title, Body),
{ok, Result} = myblog:add_post(BlogDb, Post),
...
您不需要知道Post值的详细信息,因此它的构造方式隐藏在另一个模块中的“构造函数”中。
答案 3 :(得分:0)
OOP对我来说只意味着消息传递,本地保留和保护以及隐藏状态进程, 所有事情的极端后期绑定。
Alan Kay与Dan Ingalls一起创建了Smalltalk。如果你看一下Smalltalk,就会发现它对消息的意义很明显:消息被发送到某个接收器对象,如aBumblebee.fly()。我用Smalltalk开发了近10年。我知道它是如何设计的。但是在Erlang中做的是fly(aBumblebee),其中aBumblebee也不是类的实例。
我不确定这一点,但是当你看到Erlang的演员时,他们似乎也没有交换消息。据我所知,Erlang到目前为止接收{case {...}}构造是因为必须从某个列表中检索消息。没有其他方法可以将其发送给收件人。
如果Erlang是OO,那么也不需要这些if-case语句。它们是必要的,因为没有后期绑定。在Erlang中有动态调用,是的。但是没有动态分派消息,这就是后期绑定的意思:跳转到的函数指针不是在编译时定义的,而是在运行时查找。由于Erlang中的所有函数都是全局函数,因此无论如何都不需要查找某些类。另外,我没有看到Erlang中保护的方式。如果没有类,模块或其他什么,你如何提供封装?记录所有字段都是公开的。