Erlang 编程/示例 1
外观
使用 Erlang 的对象
Erlang 是一种函数式编程语言和面向并发编程语言(Armstrong,论文,2005),但 Erlang 没有显式内置的面向对象语言特性。可以使用替代方法轻松实现面向对象编程风格。如果我们只限于单一继承,那么面向对象编程尤其容易实现。可以使用进程来表示类,使用消息来表示方法。为此,在创建每个对象时,可以创建一个表示其继承链中的祖先的进程链。方法(消息)可以沿着链传递,直到到达拥有匹配方法的进程。如果消息到达链的顶端(Object 类或高于 dev_nul 的类),那么我们可以生成一个“错误方法名”异常。每个类(进程)将在自己的递归参数调用列表中维护自己的属性(变量)。可以使用 get 和 set 等消息来访问和更新这些属性。属性存储在每个类进程中的名为 Bundle 的字典中。
包括一些使用所述技术创建 OOP 的示例代码。在程序中,我们创建了整数类的实例。它的父类 float 知道如何对实数开平方根。它的父类 complex 知道如何对负数开平方根。它的父类 matrix 知道如何对对角矩阵开平方根。
从逻辑上讲,传统的类关系保存在类图中。整数是实数。实数(float)是(复数的)子集。如果我们将(1×1)矩阵视为单个数字,那么复数是(复数矩阵的)子集。
消息(方法)发送到对象的实例。如果进程不知道如何做某事,它会将其消息(方法)传递给其父级(这种情况下的进程)。如果我们试图做一些类似于对非对角矩阵开方根的操作,它将被传递到 dev_nul 并生成错误。
start 函数创建整数类的实例。然后它要求实例计算 4 个数字的平方根:4、0.04、-4 和矩阵 [[4,0],[0,9]]。答案是:2、0.2、{2, i} 和 [[2,0],[0,3]]。
---------------------------------------------------------------- Original Each object has its own process for each of its ancestors Classes (Process chain for object Obj_1) +---------+ +---------+ | dev_nul | | dev_nul | +---------+ +---------+ / \ / \ | | | | +-----------+ +-----------+ | Object | | Object | +-----------+ +-----------+ | id | | id | | classname | | classname | | name | | name | +-----------+ +-----------+ | get() | | get() | +-----------+ +-----------+ / \ / \ | | | | +---------+ +---------+ | Matrix | | Matrix | +---------+ +---------+ +---------+ +---------+ | sqrt() | | sqrt() | +---------+ +---------+ / \ / \ | | | | +---------+ +---------+ | Complex | | Complex | +---------+ +---------+ +---------+ +---------+ | sqrt() | | sqrt() | +---------+ +---------+ / \ / \ | | | | +---------+ +---------+ | Float | | Float | +---------+ +---------+ +---------+ +---------+ | sqrt() | | sqrt() | +---------+ +---------+ / \ / \ | | | | +---------+ +---------+ | Integer | | Integer | +---------+ +---------+ +---------+ +---------+ | sqrt() | | sqrt() | +---------+ +---------+ --------------------------------------- Program output: 1> mathobjects:start(). [ [{id,#Ref<0.0.0.27>},{class_name,integer},{name,book}], 2.00000, 0.20000, {2.00000, i}, [[2.00000,0],[0,3.00000]] ]
--------------------------------------
-module(mathobjects). -compile(export_all). start()-> Obj_1 = spawn_link(mathobjects, integer, []), Id_1 = rpc(Obj_1, {get, id}), Name_1 = rpc(Obj_1, {get, name}), Class_Name_1 = rpc(Obj_1, {get, class_name}), % ------------------------------- R0 = [ Id_1, Class_Name_1, Name_1 ], R1 = rpc(Obj_1, {sqrt, 4}), R2 = rpc(Obj_1, {sqrt, 0.04}), R3 = rpc(Obj_1, {sqrt, -4}), R4 = rpc(Obj_1, {sqrt, [[4,0],[0,9]]}), [R0, R1, R2, R3, R4]. rpc(Dest, Msg) -> Dest ! {self(), Msg}, receive Answer -> Answer after 1000 -> ok end. dev_null() -> receive {From, Any} -> From ! {Any, attribute_unknown} end, dev_null(). object() -> Id = erlang:make_ref(), Class_Name = object, Bundle = dict:from_list([ {id,Id}, {class_name, Class_Name} ]), Parent = spawn(objects, dev_null, []), object(Parent, Bundle). object(Parent, Bundle) -> receive {From, {get, Attribute}} -> handle_get_attribute(Attribute, From, Bundle, Parent) end, object(Parent, Bundle). % default constructor matrix() -> Class_Name = matrix, Name = book, Parent = spawn_link(mathobjects, object, []), Parent_Class = object, Bundle = dict:from_list( [ {class_name, Class_Name}, {parent_class, Parent_Class}, {name, Name}, {parent, Parent}]), matrix(Parent, Bundle). matrix(Parent, Bundle) -> receive {From, {get, Attribute}} -> handle_get_attribute(Attribute, From, Bundle, Parent); {set, Attribute, Value} -> NBundle = handle_set_attribute(Attribute, Value, Bundle, Parent), matrix(Parent, NBundle); {From, {sqrt, [[A,B],[C,D]]}} when B==0, C==0 -> Out = [[math:sqrt(A),0],[0,math:sqrt(D)]], From ! Out; Any -> Parent ! Any end, matrix(Parent, Bundle). complex() -> Class_Name = complex, Name = book, Parent = spawn_link(mathobjects, matrix, []), Parent_Class = object, Bundle = dict:from_list( [ {class_name, Class_Name}, {parent_class, Parent_Class}, {name, Name}, {parent, Parent} ] ), complex(Parent, Bundle). complex(Parent, Bundle) -> receive {From, {get, Attribute}} -> handle_get_attribute(Attribute, From, Bundle, Parent); {set, Attribute, Value} -> NBundle = handle_set_attribute(Attribute, Value, Bundle, Parent), complex(Parent, NBundle); {From, {sqrt, Arg}} when is_list(Arg) -> Parent ! {From, {sqrt, Arg}}; {From, {sqrt, Arg}} when Arg < 0 -> Out = {math:sqrt(0-Arg), i}, From ! Out; Any -> Parent ! Any end, complex(Parent, Bundle). float() -> Class_Name = float, Name = book, Parent = spawn_link(mathobjects, complex, []), Parent_Class = object, Bundle = dict:from_list( [ {class_name, Class_Name}, {parent_class, Parent_Class}, {name, Name}, {parent, Parent}]), float(Parent, Bundle). float(Parent, Bundle) -> receive {From, {get, Attribute}} -> handle_get_attribute(Attribute, From, Bundle, Parent); {set, Attribute, Value} -> NBundle = handle_set_attribute(Attribute, Value, Bundle, Parent), float(Parent, NBundle); {From, {sqrt, Arg}} when is_list(Arg) -> Out = rpc(Parent, {sqrt, Arg}), From ! Out; {From, {sqrt, Arg}} when Arg < 0 -> Out = rpc(Parent, {sqrt, Arg}), From ! Out; {From, {sqrt, Arg}} -> Out = math:sqrt(Arg), From ! Out; Any -> Parent ! Any end, float(Parent, Bundle). integer() -> Class_Name = integer, Name = book, Parent = spawn_link(mathobjects, float, []), Parent_Class = object, Bundle = dict:from_list( [ {class_name, Class_Name}, {parent_class, Parent_Class}, {name, Name}, {parent, Parent}]), integer(Parent, Bundle). integer(Parent, Bundle) -> receive {From, {get, Attribute}} -> handle_get_attribute(Attribute, From, Bundle, Parent); {set, Attribute, Value} -> NBundle = handle_set_attribute(Attribute, Value, Bundle, Parent), integer(Parent, NBundle); {From, {sqrt, Arg}} when is_float(Arg) -> Out = rpc(Parent, {sqrt, Arg}), From ! Out; {From, {sqrt, Arg}} when is_list(Arg) -> Out = rpc(Parent, {sqrt, Arg}), From ! Out; {From, {sqrt, Arg}} when Arg < 0 -> Out = rpc(Parent, {sqrt, Arg}), From ! Out; {From, {sqrt, Arg}} -> Out = try math:sqrt(Arg) catch _AnyException -> rpc(Parent, {From, sqrt, Arg}) end, From ! Out; Any -> Parent ! Any end, integer(Parent, Bundle). % ----------------------------------------------- handle_set_attribute(Attribute, Value, Bundle, Parent) -> Found = dict:find(Attribute, Bundle), if is_tuple(Found) -> % if attribute exists then set it {ok, _} = Found, NBundle = dict:store(Attribute, Value, Bundle), NBundle; true -> Parent ! {set, Attribute, Value} end. handle_get_attribute(Attribute, From, Bundle, Parent) -> Found = dict:find(Attribute, Bundle), if is_tuple(Found) -> {ok, Value} = Found, From ! {Attribute, Value}; true -> Parent ! {From, {get, Attribute}} end.