对象(上):
对象是一个数据结构,带有一些行为。
如果需要区分上面两种情况, 那么我们就把适用于某一特定对象的方法叫做实例
方法,而把那些适用于整个类的方法叫做类方法。不过这样做只是为了方便——对于 Perl
而言,方法就是方法,只是由其第一个参数的类型来区分。
类方法 第一个参数为类
对象方法 第一个参数为对象
类里面那些生成对象实例的方
法叫构造方法
Perl的对象系统:
一个对象只不过是一个引用...恩,就是引用。
因为引用令独立的标量代表大量的数据, 所以我们不应该对把引用用于所有对象 感到奇怪。
方法调用:
不管使用哪种方法调用的形式,Perl 总是会给
构成这个方法的子过程传递一个额外的初始化参数。
如果用一个类调用该方法, 那个参数将
会是类的名字。如果用一个对象调用方法,那个参数就是对象的引用。
OO 的核心是下面这样简单的逻辑:一旦得知调用者,则可以
知道调用者的类,而一旦知道了类,就知道了类的继承关系,一旦知道了类的继承关系,那
么就知道实际调用的子过程了。
使用箭头操作符的方法调用:
我们说过有两种风格的方法调用。第一种调用方法的风格看起来象下面这样:
INVOCANT->METHOD(LIST)
INVOCANT->METHOD
当 INVOCANT 是一个
包的名字的时候,我们把那个被调用的 METHOD 看作类方法。
比如,使用类方法 summon 的构造一个类,然后在生成的对象上调用实例方法 speak,
你可以这么说:
$mage = Wizard->summon("Gandalf"); # 类方法 类方法的参数是类 Wizard
$mage->speak("friend"); # 实例方法
使用间接对象的方法调用:
间接对象的句法障碍:
引用包的类:
构造对象
可继承构造器:
和所有方法一样, 构造器只是一个子过程, 但是我们不把它看作一个子过程。 在这个例子里,
我们总是把它当作一个方法来调用——一个类方法, 因为调用者是一个包名字。
[root@wx03 5]# cat hui.pm
package hui;
sub new {
my $class=shift;
my $self = { };
bless ($self, $class);
return $self;
};
sub spawn {
my $invocant = shift;
print "\$invocant is $invocant\n";
my $class = ref($invocant) || $invocant; # 对象或者类名字 如果是对象 取类的名字
print "\$class is $class\n";
my $self = { };
bless ($self, $class);
return $self;
};
1;
[root@wx03 5]# cat a2.pl
use hui;
$ua=hui->new();
print $ua;
print "\n";
$ua->spawn;
[root@wx03 5]# perl a2.pl
hui=HASH(0xd8d160)
$invocant is hui=HASH(0xd8d160)
$class is hui
初始器:
sub new {
my $invocant = shift;
my $class = ref($invocant) || $invocant;
my $self = { @_ }; # 剩下的参数变成属性
bless($self, $class); # 给予对象性质
return $self;
}
更灵活一些,你可以用缺省键字/数值对设置你的构造器,这些参数可以由用户在使用的时
候通过提供参数而覆盖掉:
[root@wx03 5]# cat Horse.pm
package Horse;
sub new {
my $invocant = shift;
my $class = ref($invocant) || $invocant;
my $self = {
color => "bay",
legs => 4,
owner => undef,
@_, # 覆盖以前的属性
};
return bless $self, $class;
};
1;
[root@wx03 5]# cat a3.pl
use Horse;
$ed = Horse->new;
use Data::Dumper;
$str=Dumper($ed);
print "\$str is $str\n";
$stallion = Horse->new(color => "black"); # 四腿黑马
$str=Dumper($stallion);
print "\$str is $str\n";
[root@wx03 5]# perl a3.pl
$str is $VAR1 = bless( {
'owner' => undef,
'legs' => 4,
'color' => 'bay'
}, 'Horse' );
$str is $VAR1 = bless( {
'owner' => undef,
'legs' => 4,
'color' => 'black'
}, 'Horse' );
当把这个 Horse 构造器当作实例方法使用的时候,它忽略它的调用者现有的属性。
任何碰巧创建和返回一个对象的方法都是实际上的构造器
perl 把对象转换成散列:
[root@wx03 5]# cat a4.pl
use Horse;
use Data::Dumper;
$steed = Horse->new(color => "dun");
$str=Dumper($steed);
print "\$str is $str\n";
print "111111111111\n";
print %$steed;
print "\n";
print "2222222222\n";
%hash=%$steed;
print $hash{color};
print "\n";
[root@wx03 5]# perl a4.pl
$str is $VAR1 = bless( {
'legs' => 4,
'owner' => undef,
'color' => 'dun'
}, 'Horse' );
111111111111
legs4ownercolordun
2222222222
dun
//**********
sub new {
my $invocant = shift;
my $class = ref($invocant) || $invocant;
my $self = {
color => "bay",
legs => 4,
owner => undef,
@_, # 覆盖以前的属性
};
return bless $self, $class;
}
sub clone {
my $model = shift;
my $self = $model->new(%$model, @_); ##把$model对象转成hash,@_ 是传入的参数 这里是owner => "EquuGen Guild, Ltd."
#$model 作为new的第一个参数,会提取类名
return $self; # 前面被 ->new 赐福过了
}
类继承:
Perl 是这样实现继承的:一个包的@ISA 数组里的每个元素都保留另外一个包的名字,
当缺失方法的时候就搜索这些包。
比如,下面的代码把Horse类变成Critter类的子类。
(我们用our声明@ISA,因为它必须是一个包变量,而不能是my声明的词法作用域变量)。
package Horse;
our @ISA = "Critter";
你现在应该可以在原先Critter使用的任何地方使用Horse类或者对象了。
如果你的新类通过了这样的空子类测试,那么你就可以认为Critter是一个正确的基类,
可以用于继承。
[root@wx03 5]# cat Critter.pm
package Critter;
sub new {
my $self = {};
my $invocant = shift;
my $class = ref($invocant) || $invocant;
my ($name)=@_;
my $self = {
"name" =>$name
};
bless $self, $class; # Use class name to bless() reference
return $self;
};
sub sum2 {
$self=shift;
my $a=shift;
my $b=shift;
return $a + $b;
};
sub fun1 {
$self=shift;
my $a=shift;
my $b=shift;
return $a / $b;
}
1;
[root@wx03 5]# cat a4.pl
use Horse;
use Data::Dumper;
$steed = Horse->new(color => "dun");
print $steed->fun1(10,2);
print "\n";
[root@wx03 5]# perl a4.pl
5
你现在应该可以在原先 Critter 使用的任何地方使用 Horse 类或者对象了。