对象(上):

第十二章 对象(上):

12.1 简单复习一下面向对象的语言:

对象是一个数据结构,带有一些行为。我们通常把这些行为称为对象的直接动作,有时候

可以把这些对象拟人化。

作为一个类的实例,对象从中获益,取得其行为。类定义方法:就是那些应用于类和它的事例的性质。


如果需要区分上面两张情况:

1.那么我们就把适用于某一特定对象的方法叫做实例方法

2.而把那些适用于整个类的方法叫做类方法。

不过这样做只是为了方便---对于Perl而言,方法就是方法,只是由其第一个参数的类型来区分。


你可以把实例方法看作一个由特定对象执行的某种动作


类里面那些生成实例的方法叫构造方法。


一个类可以从父类中继承方法,父类也叫基类或者超级类。如果类是这样生成的,那么它叫派生类或者子类

[root@node01 ~]# cat Pkg01.pm 
package Pkg01;
sub fun1 {
    my $self=shift;
    my $a=shift;
    my $b=shift;
    print $a * $b +3;};
1;



[root@node01 ~]# cat Pkg02.pm 
package Pkg02;
sub fun2 {
    my $self=shift;
    my $a=shift;
    my $b=shift;
    print $a * $b +4;};
1;


[root@node01 ~]# cat Pkg03.pm 
package Pkg03;
sub fun3 {
    my $self=shift;
    my $a=shift;
    my $b=shift;
    print $a * $b + 4;};
1;

[root@node01 ~]# cat Scan.pm 
package Scan;
use base qw(Pkg01 Pkg02 Pkg03);
sub new {
my $invocant = shift;
my $class = ref($invocant) || $invocant;
my $self = {
};
bless $self, $class;
 return $self;
};

sub fun4 {
 my $self=shift;
 my $a=shift;
 my $b=shift;
 print $a + $b;
};
1;

[root@node01 ~]# cat p1.pl 
use Scan;
$ua=Scan->new();
$ua->fun1(4,5);
print "
";
$ua->fun2(6,7);
print "
";
$ua->fun3(8,5);
print "
";
$ua->fun4(3,6);
print "
";
[root@node01 ~]# perl p1.pl 
23
46
44
9



12.2 Perl 的对象系统

Perl 没有为定义对象,类或者方法提供任何特殊的语法。

相反,它使用现有的构造器来实现这三种概念。

一个对象只不过是一个引用 嗯,就是引用

因为引用令独立的标量代表大量的数据,所以我们不应该把引用用于所有对象 感到奇怪。

一个类只是一个包

12.3 方法调用:

方法是对象系统的核心,意味它们为实现所有魔术提供了抽象层。

你不是直接访问对象里的一块数据区,而是调用一个实例方法,

你不是直接调用某个包里的子过程,而是调用一个类的方法。


不管使用哪种方法调用的形式,Perl总是会给构成这个方法的子过程传递一个额外的初始化参数。


如果用一个类调用该方法,那么参数将会是类的名字

如果用一个对象调用方法,那么参数就是对象的引用

12.3.1 使用箭头操作符的方法调用:

我们说挂有两种风格的方法调用,第一种调用的方法的风格看起来像下面这样:

INVOCANT->METHOD(LIST)

INVOCANT->METHOD


而当INVOCANT 是一个包的名字的时候,我们把那个调用的METHOD看作类的方法。

比如,使用类方法summon 的构造一个类,然后再生成的对象上调用实例方法speak,你可以这么说:

$mage = Wizard->summon("Gandalf"); # 类方法
$mage->speak("friend"); # 实例方法




[root@node01 perl]# cat Wizard.pm 
package Wizard;
sub summon {
my $invocant = shift;
my $class = ref($invocant) || $invocant;
print "$class==$class
";
my $self = {
};
bless $self, $class;
 return $self;
};


sub speak {
  my $self=shift;
  print "freend*5";
};
1;

[root@node01 perl]# cat Wizard.pm 
package Wizard;
sub summon {
my $invocant = shift;
my $class = ref($invocant) || $invocant;
print "$class==$class
";
my $self = {
};
bless $self, $class;
 return $self;
};


sub speak {
  my $self=shift;
  print "freend*5";
};
1;
 
[root@node01 perl]# cat a2.pl 
use Wizard;
$mage = Wizard->summon("Gandalf"); # 类方法
$mage->speak("friend"); # 实例方法
[root@node01 perl]# perl a2.pl 
$class==Wizard
freend*5[root@node01 perl]# 

12.3.2 使用间接对象的方法调用;

第二种风格的方法调用起来像这样:

METHOD INVOCANT (LIST)

METHOD INVOCANT LIST

METHOD INVOCANT



12.3.4 引用包的类;

12.4 构造对象

所有对象都是引用,但不是所有引用都是对象

一个引用不会作为对象运转,除非引用它的东西有特殊标记告诉Perl它属于哪个包。

bless 函数接收一个或者两个参数,第一个参数是引用,而第二个是要把引用赐福(bless)成的包。

如果忽略第二个参数,则使用当前包:

[root@node01 perl]# cat Luo.pm 
package Luo;
sub new {
 my $invocant = shift;
 my $class = ref($invocant) || $invocant;
 print "$class==$class
";
 my $obj = {
 } ;
 bless $obj, $class;
 return $obj;
};

sub fun1 {
  my $self=shift;
  my $a=shift;
  my $b=shift;
  return $a + $b;
};
1;
[root@node01 perl]# cat a4.pl 
use Luo;
my $ua=Luo->new();
print $ua->fun1(44,33);
[root@node01 perl]# perl a4.pl 
$class==Luo
77[root@node01 perl]# 


12.4.1 可继承构造器:

和所有方法一样,构造器只是一个子过程,但是我们不把它看作一个子过程。

在这个例子里,我们总是把它当作一个方法调用---一个类方法,因为调用者是一个包的名字。


方法调用:

[root@node01 perl]# cat Luo.pm 
package Luo;
sub new {
 my $invocant = shift;
 my $class = ref($invocant) || $invocant;
 print "$class==$class
";
 my $obj = {
 } ;
 bless $obj, $class;
 return $obj;
};

sub fun1 {
  my $self=shift;
  my $a=shift;
  my $b=shift;
  return $a + $b;
};
1;
[root@node01 perl]# cat a4.pl 
use Luo;
my $ua=Luo->new();
print $ua->fun1(44,33);

[root@node01 perl]# perl a4.pl 
$class==Luo
$self==Luo=HASH(0x14af160)
77[root@node01 perl]# 


子过程调用:
[root@node01 perl]# cat a5.pl 
use Luo;
print Luo::fun1(44,33);
[root@node01 perl]# perl a5.pl 
$self==44
33[root@node01 perl]# 



$type = "Spider";
$shelob = $type->spawn; # 和 "Spider"->spawn 一样
这些仍然是类方法,不是实例方法,因为它的调用者持有的是字串而不是一个引用。


[root@node01 perl]# cat Luo.pm 
package Luo;
sub new {
 my $invocant = shift;
 print "$invocant==$invocant
";
 my $class = ref($invocant) || $invocant;
 print "$class==$class
";
 my $obj = {
 } ;
 bless $obj, $class;
 return $obj;
};

sub fun1 {
  my $self=shift;
  print "$self==$self
";
  my $a=shift;
  my $b=shift;
  return $a + $b;
};
1;
[root@node01 perl]# cat a4.pl 
use Luo;
my $ua=Luo->new();
my $xx=$ua->new();
print $ua->fun1(44,33);
[root@node01 perl]# perl a4.pl 
$invocant==Luo
$class==Luo
$invocant==Luo=HASH(0xdb3160)
$class==Luo
$self==Luo=HASH(0xdb3160)
77[root@node01 perl]# 










12.4.2 初始器:

大多数对象维护的信息是由对象的方法间接操作的,到目前为止我们的所有构造器都创建了空散列,

但是我们没有理由让它们这么空着。

[root@node01 perl]# cat Horse.pm 
package Horse;
sub new {
my $invocant = shift;
my $class = ref($invocant) || $invocant;
my $self = { @_ }; # 剩下的参数变成属性
bless($self, $class); # 给予对象性质
return $self;
};

sub fun1 {
  my $self=shift;
  print $self->{'name'}."xxxx"."
";;
  print $self->{'color'}."yyyy"."
";
};
1;

[root@node01 perl]# cat a6.pl 
use Horse;
my $ua=Horse->new(name => "shadowfax", color => "white");
$ua->fun1();
[root@node01 perl]# perl a6.pl 
shadowfaxxxxx
whiteyyyy


你可以把你的构造器命名为任意的东西,任何碰巧创建和返回一个对象的方法都是实际上的构造器。


[root@node01 perl]# 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;
};
sub fun1 {
  my $self=shift;
  print $self->{'name'}."xxxx"."
";;
  print $self->{'color'}."yyyy"."
";
};
1;



[root@node01 perl]# 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;
};
sub fun1 {
  my $self=shift;
  print $self->{'name'}."xxxx"."
";;
  print $self->{'color'}."yyyy"."
";
};
1;

[root@node01 perl]# cat a6.pl 
use Horse;
my $ua=Horse->new(name => "shadowfax", color => "white");
$ua->fun1();
[root@node01 perl]# perl a6.pl 
shadowfaxxxxx
whiteyyyy

12.5 类继承

对Perl的对象系统剩下的内容而言,从一个类继承另外一个类并不需要给这门语言增加特殊的语法。

当你调用一个方法的时候,如果Perl在调用者的包里找不到这个子过程,

packge Mule;  
use base ("Horse", "donkey"); # 声明一个超类  

它是下面东西的缩写:  
package Mule;  
BEGIN {  
our @ISA = ("Horse", "Donkey");  
require Horse;  
require Donkey;  
}  




/***************************************************
[root@node01 zhao]# cat Mule.pm 
package Mule;
use base ("Horse", "donkey");
sub new {
my $invocant = shift;
my $class = ref($invocant) || $invocant;
my $self = { @_ }; # 剩下的参数变成属性
bless($self, $class); # 给予对象性质
return $self;
};

sub fun3 {
 my $self=shift;
 my $a=shift;
 my $b=shift;
 return $a + $b +33;
};
1;

[root@node01 zhao]# cat Horse.pm 
package Horse;
sub fun1 {
  my $self=shift;
  my $a=shift;
  my $b=shift;
  return $a + $b +11;

};
1


[root@node01 zhao]# cat donkey.pm 
package donkey;
sub fun2 {
  my $self=shift;
  my $a=shift;
  my $b=shift;
  return $a + $b +22;
};
1


[root@node01 zhao]# cat a1.pl 
use  Mule;

my $ua=Mule->new();
print $ua->fun1(11,22);
print "
";
print $ua->fun2(11,22);
print "
";
print $ua->fun3(11,22);
print "
";


[root@node01 zhao]# perl a1.pl 
44
55
66



等价于:
[root@node01 zhao]# cat Mule.pm
package Mule;
BEGIN {  
our @ISA = ("Horse", "donkey");  
require Horse;  
require donkey;  
}; 
sub new {
my $invocant = shift;
my $class = ref($invocant) || $invocant;
my $self = { @_ }; # 剩下的参数变成属性
bless($self, $class); # 给予对象性质
return $self;
};

sub fun3 {
 my $self=shift;
 my $a=shift;
 my $b=shift;
 return $a + $b +33;
};
1;
[root@node01 zhao]# cat a1.pl 
use  Mule;

my $ua=Mule->new();
print $ua->fun1(11,22);
print "
";
print $ua->fun2(11,22);
print "
";
print $ua->fun3(11,22);
print "
";


[root@node01 zhao]# perl a1.pl 
44
55
66





package Mule;
BEGIN {  
our @ISA = ("Horse", "donkey");  
require Horse;  
require donkey;  
};

表示 Mule 继承了Horse类和donkey类



                                    
原文地址:https://www.cnblogs.com/hzcya1995/p/13350744.html