Chinaunix首页 | 论坛 | 博客
  • 博客访问: 314104
  • 博文数量: 118
  • 博客积分: 313
  • 博客等级: 二等列兵
  • 技术积分: 615
  • 用 户 组: 普通用户
  • 注册时间: 2011-11-12 22:51
文章分类

全部博文(118)

文章存档

2012年(68)

2011年(50)

分类:

2011-12-15 02:03:22

原文地址:一个Erlang例子的分析 作者:sudayly

Programming Erlang第四章中有个题目是使用表模拟数据库操作db.erl,定义的操作有
% 初始化一个新的Db
new()
% 清空Db
delete(Db) 
% 把数据写入库
write(Key, Element, Db)
% 搜索Db,返回对应元素
read(Key, Db) 
% 返回值为Element的Key列表
match(Element, Db) 

实现比较好实现,不过因为Erlang是函数式语言,缺少状态机制,因此每个操作都需要传入Db参数。这种函数就像传统的C语言函数一样,需要传入数据结构。

Programming Erlang的第六章讲解了并发编程的几个模式,使用Server-Client模式对上述问题进行封装,得到my_db.erl。使用my_db.erl,我们就可以这么写代码:
my_db:start(),
my_db:write(foo, bar),
my_db:read(foo),
my_db:match(bar).

而使用db.erl的话只能写出这样的代码:
Db = db:new(),
NewDb = db:write(foo, bar, Db),
db:read(foo, NewDb),
db:match(bar, NewDb).

如果熟悉C语言和C++语言,那么很容易得出,第一种写法类似类,里面封装了个Db的成员变量,而后者更像是C语言写的。

现在来分析下my_db.erl的实现。my_db首先启动了个进程,该进程做的就是在本小节开头提到的Db操作。然后,my_db使用函数封装了进程间消息发送与接收的处理(这些函数称为Client Functions)。从这个角度来看,my\_db和类的原理是一致的,向外提供操作接口,内部又具有成员变量(这里指的是操作的Db是全部函数共享的)。

my_db.erl的代码如下:
-module(my_db).
-export([start/0,stop/0,write/2,delete/1,read/1,match/1]).
-export([init/0]).

start() ->
    register(my_db, spawn(?MODULE, init, [])),ok.
stop() -> call({stop}).
write(Key, Element) -> call({write, {Key, Element}}). 
delete(Key) -> call({delete, {Key}}).
read(Key) -> call({read, {Key}}).
match(Element) -> call({match, {Element}}).

call(Msg) ->
    my_db ! {request, self(), Msg},
    receive {reply, Reply} -> Reply end.    

reply(From, Msg) ->
    From ! {reply, Msg}.

init() ->
    loop(db:new()).

loop(Db) ->
    receive
{request, From, {stop}} ->
   db:destroy(Db),
   reply(From, ok);
{request, From, {write, {Key, Element}}} ->
   NewDb = db:write(Key, Element, Db),
   reply(From, ok),
   loop(NewDb);
{request, From, {delete, {Key}}} ->
   NewDb = db:delete(Key, Db),
   reply(From, ok),
   loop(NewDb);
{request, From, {read, {Key}}} ->
   Result = db:read(Key, Db),
   reply(From, Result),
   loop(Db);
{request, From, {match, {Element}}} ->
   Result = db:match(Element, Db),
   reply(From, Result),
   loop(Db)
    end.

db.erl的代码如下:
-module(db).
-export([new/0, destroy/1, write/3, delete/2, read/2, match/2]).

new() ->
    [].

destroy(_) ->
    [].

write(Key, Element, Db) ->
    [{Key, Element}|Db].

delete(Key, [{Key, _}|T]) ->
    delete(Key, T);
delete(Key, [H|T]) ->
    [H|delete(Key, T)];
delete(_, []) ->
    [].

read(Key, [{Key, Element}|_]) ->
    {ok, Element};
read(Key, [_|T]) ->
    read(Key, T);
read(_, []) ->
    {error, instance}.

match(Element, [{Key, Element}|T]) ->
    [Key|match(Element, T)];
match(Element, [_|T]) ->
    match(Element, T);
match(_, []) ->
    [].

这里值得注意的一点是,db.erl是我在读Programming Erlang第四章的时候编写的,而my_db.erl是在读第六章的时候编写的。而my_db.erl用到db.erl,在其的编写过程中我并未改动db.erl。db.erl规定了进程所做的事情,而my_db.erl规定了客户端使用方法,并封装了个Db,Db其实就是指数据源了。
阅读(670) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~