Journal(2005) | Blog(2006) | RandomLink | WhoAmI | LiveBookmark | HomePage

<<Previous: Share the URLs with u (Apr. 2005)  >>Next: $Class[2] = 'Class::Trigger';

$Class[1] = 'Class::Data::Inheritable';

Category: Modules   Keywords: Class::Data::Inheritable

Verbiage

It's the second Class. ;)
本来打算要讲的是 Class::Trigger,可得先介绍下 Class::Data::Inheritable
本来打算简单介绍的,可一写就收不了手了。:)

Class::Data::Inheritable - Inheritable, overridable class data - 类数据继承与覆盖。
该模块能将类数据做为一个整体来保存,并且可以被子类继承和覆盖。
该模块里就一个函数:mk_classdata

例子

我们先举个例子(源代码里的例子),然后再分析源代码。
package Pere::Ubu;
use base qw(Class::Data::Inheritable);

Pere::Ubu->mk_classdata('Suitcase');

Pere::Ubu->Suitcase('Red');
my $suitcase = Pere::Ubu->Suitcase;
mk_classdata 能生成 Suitcase 函数并能存取,这点于 Class-Accessor 有点像,但 Class::Data::Inheritable 最主要的功能不在这,在于继承和覆盖。
package Raygun;
use base qw(Pere::Ubu);
  
# Raygun's suitcase is Red.
my $suitcase = Raygun->Suitcase;
这样 Raygun 继承了类 Pere::Ubu 的数据,一旦修改 Pere::Ubu 的数据,Raygun 就会自动改变。
# Both Raygun's and Pere::Ubu's suitcases are now Blue
Pere::Ubu->Suitcase('Blue');
如果 Raygun 想自己控制数据而不随着 Pere::Ubu 的改变而改变的话可以覆盖数据(设置自己的数据)。
# Raygun has an orange suitcase, Pere::Ubu's is still Blue.
Raygun->Suitcase('Orange');
这样以后 Pere::Ubu 改变数据也不会影响 Raygun 了。

源码分析

 =1= sub mk_classdata {
 =2=    my ($declaredclass, $attribute, $data) = @_;

 =3=    my $accessor = sub {
 =4=        my $wantclass = ref($_[0]) || $_[0];

 =5=        return $wantclass->mk_classdata($attribute)->(@_)
                if @_>1 && $wantclass ne $declaredclass;

 =6=        $data = $_[1] if @_>1;
 =7=        return $data;
 =8=    };

 =9=    my $alias = "_${attribute}_accessor";
 =10=   *{$declaredclass.'::'.$attribute} = $accessor;
 =11=   *{$declaredclass.'::'.$alias}     = $accessor;
 =12= }
=2= 中 $declaredclass 是声明 mk_classdata 的包名,比如 Pere::Ubu->mk_classdata('Suitcase'); 时该变量就为 Pere::Ubu, $attribute 是 Suitcase, 而这里的 $data 是给 =5= 行准备的。
=3= 是声明一个匿名函数,并引用给 $accessor
=4= ref($_[0]) || $_[0] 是为了得到所调用该函数的包名。比如 Pere::Ubu->Suitcase('Red'); 时为 Pere::Ubu; 而 Raygun->Suitcase('Orange'); 时为 Raygun。注意这里的 $_[0] 是调用该匿名函数所传递进来的,所以 $wantclass 是该函数所调用的对象。
=5= 注意这里的 @_ 是调用匿名函数的参数,不是 mk_classdata 的参数。 如果参数大于1,就是是Raygun->Suitcase('Orange'); 而不是 my $suitcase = Raygun->Suitcase;,而且 $wantclass 和 $declaredclass 不同时(Raygun->Suitcase('Orange');时 $declaredclass 是 Pere::Ubu, 而调用的是 Raygun),重新调用 mk_classdata 并把 @_ 传递过去($Raygun->mk_classdata,这里就传递了 $data)
=6= 这句是给 Pere::Ubu->Suitcase('Red'); 准备的。
=7= 这样不管是新建立的(=5=)还是单单读取(=6=)都有值返回。
=10= 这句是最紧要的,就是在声明包的符号表里建立 $attribute 到匿名函数的关系。这样就能使用 Pere::Ubu->Suitcase 了
=9= 和 =11= 是另外在符号表里声明了 _${attribute}_accessor(这里是_Suitcase_accessor)。这个的用途是你在继承包里定义 Suitcase 时又想调用原来的 Suitcase, 这时就可以调用 _Suitcase_accessor(这个其实可以用NEXT模块实现)

希望我讲得够明白。慢慢读懂它,你的 Perl 水平就提高上去了。一起进步。:)
Class::* 模块都用了很多技巧,魔法/magic 一样。

<<Previous: Share the URLs with u (Apr. 2005)  >>Next: $Class[2] = 'Class::Trigger';

Options: +Del.icio.us

Related items Created on 2005-04-27 17:57:39, Last modified on 2005-04-27 23:18:34
Copyright 2004-2005 All Rights Reserved. Powered by Eplanet && Catalyst 5.62.