• 第十二章 对象(上):


    第十二章  对象(上):
    
    对象是一个数据结构,带有一些行为。
    
    作为一个类的实例,对象从中获益,取得其行为。
    
    类定义方法: 就是那些应用于类和它的事例的性质。
    
    
    12.2  Perl 的对象系统:
    
    一个对象只不过是一个引用
    
    
    因为引用令独立的标量代表大量的数据,
    
    一个类只是一个包:
    
    
    一个包当作一个类---通过使用包的子过程来执行类的方法,以及通过使用包变量来保存类的全局数据。
    
    
    一个方法只是一个子过程
    
    12.3 方法调用:
    
    
    
    方法是对象系统的核心, 如果用一个对象调用方法,那个参数就是对象的引用。
    
    
    对于类调用者 ,调用者是包的名字。
    
    对于一个实例,调用者是一个声明对象的引用。
    
    
    12.3.1  使用箭头操作符的方法调用:
    
    我们说过有两种风格的方法调用。第一种调用方法的风格看起来象下面这样:
    INVOCANT->METHOD(LIST)
    INVOCANT->METHO
    
    
    请不要把-> 和=>混淆,双管箭头其神奇逗号的作用
    
    
    而当INVOCANT是一个包的名字的时候,我们把那个被调用的METHOD看作类的方法。
    
    
    比如,使用类方法 summon 的构造一个类,然后在生成的对象上调用实例方法 speak,
    你可以这么说:
    
    $mage = Wizard->summon("Gandalf"); # 类方法
    
    $mage->speak("friend"); # 实例方法
    
    
    summon和speark方法都是有Wizard 类定义的  或者是从一个它继承来的类定义的。
    
    
    因为箭头操作符是左关联的,你甚至可以把这两个语句合并成一条:
    
    Wizard->summon("Gandalf")->speak("friend");
    
    12.3.2   使用间接对象的方法调用:
    
    
    12.3.3  间接对象的句法障碍:
    
    
    12.3.4  引用包的类:
    
    
    间接对象风格的方法调用最后还有一种可能的混淆,
    
    
    12.4 构造对象:
    
    
    所有对象都是引用,但不是所有引用都是对象。
    
    一个引用不会作为对象运转,除非引用它的东西又特殊标记告诉Perl它属于哪个包。
    
    
    
    把一个引用和一个包名字标记起来(因此也和包中的类标记起来了,因为一个类就是一个包)
    
    的动作被称作赐福(blessing)
    
    
    你可以把赐福(bless)看作把一个引用转换成一个对象,尽管更准确地说是它把该引用转换成一个对象引用
    
    
    
    bless 函数接收一个或者两个参数,第一个参数是一个引用,而第二个是要把引用赐福(bless)成的包。
    
    如果忽略第2个参数,则使用当前包
    
    
    zjzc01:/root/big2# cat p1.pm
    package p1;
    use Data::Dumper;
    sub new_regular {
       my ($name,$age,$starting_position,$monthly_salary)=@_;
          my $employee = {
             "name" =>$name,
             "age" =>$age,
              "position" =>$starting_position,
               "montly_salary" =>$monthly_salary,
                     };
              bless ($employee);  ## 返回对象引用
              return $employee;
                       };
    1;
    
    
    zjzc01:/root/big2# cat p1.pl
    unshift(@INC,"/root/big2");  
    require p1;  
    use Data::Dumper;
    $var=p1::new_regular(a,b,c,d);
     my $xx= Dumper($var);    
    print $xx;    
    print "
    "; 
    
    
    zjzc01:/root/big2# perl p1.pl
    $VAR1 = bless( {
                     'position' => 'c',
                     'name' => 'a',
                     'montly_salary' => 'd',
                     'age' => 'b'
                   }, 'p1' );
    
    
    
    这里我们使用了一个指向匿名散列的引用,也就是人们通常拿来做他们的对象的数据结构的东西。
    
    毕竟,散列极为灵活。
    
    
    这就是如何制作对象,只需要使用某事的引用,通过把他赐福(bless)到一个包里给他赋一个类
    
    
    zjzc01:/root/big2# cat Critter.pm 
    package Critter;
    sub spawn {
    my $self = {}; # 指向一个空的匿名散列
    bless $self, "Critter"; # 把那个散列作成一个 Critter 对象
    return $self; # 返回新生成的 Critter
    };
    1;
    zjzc01:/root/big2# cat p2.pl 
    unshift(@INC,"/root/big2");  
    require Critter;
    use Data::Dumper;
    $var=Critter->spawn;
     my $xx= Dumper($var);    
    print $xx;    
    print "
    ";
    zjzc01:/root/big2# perl p2.pl 
    $VAR1 = bless( {}, 'Critter' );
    
    12.4.1  可继承构造器:
    
    和所有方法一样,构造器只是一个子过程,但是我们不把它看作一个子过程。
    
    
    
    在这个例子里,我们总是把它当作一个方法来调用-----一个类方法,因为调用者是一个包名字。
    
    
    方法调用和普通的子过程调用有两个区别。
    
    
    12.4.2  初始器:
    
    假设一个 Horse 类有一些实例属性,比如 "name" 和 "color":
    $steed = Horse->new(name => "shadowfax", color => "white");
    
    
    sub new  
    {  
      my ($this,  
          $proto,             # Optional protocol to use for pinging  
          $timeout,           # Optional timeout in seconds  
          $data_size,         # Optional additional bytes of data  
          $device,            # Optional device to use  
          $tos,               # Optional ToS to set  
          ) = @_;  
      my  $class = ref($this) || $this;  
      my  $self = {};  
      my ($cnt,               # Count through data bytes  
          $min_datasize       # Minimum data bytes required  
          );  
      
      bless($self, $class);  
      
      
      
    其中$class is Net::Ping  
    
    
    第一个参数 $this 是类的名字
    
    
    jrhmpt01:/root# cat a3.pl   
    use Net::Ping;  
    $p = Net::Ping->new("icmp");  
    use Data::Dumper;    
     my $xx= Dumper($p);        
    print "111111111
    ";    
    print $xx;        
    print "
    "; 
    
    
    
    
    
    
    zjzc01:/root/big2# cat x1.pm
    package x1;
    use Data::Dumper;
    sub new {
    my $invocant = shift;
    my $class = ref($invocant) || $invocant;
    print "$class is $class
    ";
    my $self = { @_ }; # 剩下的参数变成属性
    bless($self, $class); # 给予对象性质
     my $xx= Dumper($self);        
    print "111111111
    ";    
    print $xx;        
    print "
    ";
    return $self;
    };
    1;
    
    zjzc01:/root/big2# cat x1.pl
    unshift(@INC,"/root/big2");  
    require x1;  
    use Data::Dumper;
    $var=x1->new('zyj-test');
     my $xx= Dumper($var);    
    print $xx;    
    print "
    "; 
    
    zjzc01:/root/big2# perl x1.pl
    $class is x1
    111111111
    $VAR1 = bless( {
                     'zyj-test' => undef
                   }, 'x1' );
    
    $VAR1 = bless( {
                     'zyj-test' => undef
                   }, 'x1' );
    
    
    zjzc01:/root/big2# cat x1.pl
    unshift(@INC,"/root/big2");  
    require x1;  
    use Data::Dumper;
    $var=x1->new('zyj-test');
     my $xx= Dumper($var);    
    print $xx;    
    print "
    "; 
    
    
    这回我们用一个名字叫new的方法做该类的构造器,这样就可以把那些C++程序员哄得相信这些都是正常的。
    
    
    任何碰巧创建和返回一个对象的方法都是实际上的构造器。
    
    
    在Tk模块中的构造器名为为它们创建的窗口构件
    
    zjzc01:/root/big2# 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;
    zjzc01:/root/big2# cat Horse.pl
    unshift(@INC,"/root/big2");  
    require Horse;  
    use Data::Dumper;
    $ed = Horse->new; # 四腿湾马
     my $xx= Dumper($ed);    
    print $xx;    
    print "
    "; 
    print "2222222222
    ";
    $stallion = Horse->new(color => "black"); # 四腿黑马
     my $xx= Dumper($stallion);
    print $xx;
    print "
    ";
    print "2222222222
    ";
    zjzc01:/root/big2# perl Horse.pl
    $VAR1 = bless( {
                     'owner' => undef,
                     'color' => 'bay',
                     'legs' => 4
                   }, 'Horse' );
    
    2222222222
    $VAR1 = bless( {
                     'owner' => undef,
                     'color' => 'black',
                     'legs' => 4
                   }, 'Horse' );
    
    2222222222
    
    当把这个Horse 构造器当作实例方法使用的时候,它忽略它的调用者现有的属性。你可以涉及第2个构造器,
    
    把它当作实例方法来调用
    
    
    
    12.5  类继承:
    
    
    对Perl 的对象系统剩下的内容而言,从一个类继承另外一个类并不需要给这门语言增加特殊的语法。
    
    
    当你调用一个方法的时候,如果Perl 在调用者的包里找不到这个子过程,那么它就检查@ISA 数组。
    
    
    Perl 是这样实现继承的:一个包的@ISA 数组里的每个元素都保存另外一个包的名字,
    
    当缺失方法的时候就搜索这些包。
    
    比如下面的代码把Horse类变成Critter类的子类 
    
    
    
    
    zjzc01:/root/big2# cat Horse.pm
    package Horse;
    require Critter;
    our @ISA="Critter";
    sub new {
    my $invocant = shift;
    my $class = ref($invocant) || $invocant;
    my $self = {
    color => "bay",
    legs => 4,
    owner => undef,
    @_, # 覆盖以前的属性
    };
    return bless $self, $class;
    };
    1;
    
    zjzc01:/root/big2# cat Critter.pm 
    package Critter;
    sub spawn {
    my $self = {print "122334456"}; # 指向一个空的匿名散列
    bless $self, "Critter"; # 把那个散列作成一个 Critter 对象
    return $self; # 返回新生成的 Critter
    };
    1;
    
    
    zjzc01:/root/big2# cat Horse.pl
    unshift(@INC,"/root/big2");  
    require Horse;  
    use Data::Dumper;
    $ed = Horse->new; # 四腿湾马
    $x=Critter->spawn;
    print "
    ";
    
    
    zjzc01:/root/big2# perl Horse.pl
    122334456
    
    
    你现在应该可以在原来Critter 使用的任何地方Horse类或者对象了,如果你的新类
    
    zjzc01:/root/big2# cat p2.pl 
    unshift(@INC,"/root/big2");  
    require Horse;
    use Data::Dumper;
    $var=Critter->spawn;
     my $xx= Dumper($var);    
    print $xx;    
    print "
    ";
    print "2222222222222
    ";
    $ed = Horse->new; # 四腿湾马
     my $xx= Dumper($var);
    print $xx;
    print "
    ";
    
    
    zjzc01:/root/big2# perl p2.pl 
    122334456$VAR1 = bless( {
                     '1' => undef
                   }, 'Critter' );
    
    2222222222222
    $VAR1 = bless( {
                     '1' => undef
                   }, 'Critter' );
    
    
    
    
    
    zjzc01:/root/big2# cat Horse.pl
    unshift(@INC,"/root/big2");  
    require Horse;  
    use Data::Dumper;
    $ed = Horse->new; # 四腿湾马
     my $xx= Dumper($ed);
    print $xx;
    print "
    ";
    $x=Critter->spawn;
     my $xx= Dumper($x);
    print $xx;
    print "
    ";
    zjzc01:/root/big2# perl Horse.pl
    $VAR1 = bless( {
                     'owner' => undef,
                     'color' => 'bay',
                     'legs' => 4
                   }, 'Horse' );
    
    122334456$VAR1 = bless( {
                     '1' => undef
                   }, 'Critter' );
    
    

  • 相关阅读:
    面试题(8)之 在线题
    deepin深度学习环境配置
    ubuntu18.04配置nvidia docker和远程连接ssh+远程桌面连接(一)
    ubuntu18.04配置nvidia docker和远程连接ssh+远程桌面连接(三)
    ubuntu18.04配置nvidia docker和远程连接ssh+远程桌面连接(二)
    阅读博客后结合自身经历的心得体会
    软件工程学习后问题解答
    软件工程课后总结与反思
    学霸数据处理项目之数据处理网页以及后台以及C#代码部分开发者手册
    学霸数据处理项目之数据处理框架开发者手册
  • 原文地址:https://www.cnblogs.com/hzcya1995/p/13351085.html
Copyright © 2020-2023  润新知