• Perl中的面向对象编程


    一、模块简介

      模块(module)就是Perl包(package)。Perl的对象基于对包中数据项的引用。

      在用其它语言进行面向对象编程时,先声明一个类然后创建该类的对象(实例),特定类所有对象的行为方式是相同的,由类方法确定,可以通过定义新类或从现存类继承来创建类。

    • 类是一个Perl包,其中包含提供对象方法的类;
    • 方法是一个Perl子程序,类名是其第一个参数;
    • 对象是对类中数据项的引用。

    二、Perl中的类

      一个Perl类是一个包。Perl5用双冒号(::)来标识基本类和继承类(之类)。

      Perl中的继承只继承方法,必须使用自己的机制来实现数据的继承。

      因为每个类是一个包,所以它有自己的名字空间及自己的符号名关联数组(详见第x章关联数组),每个类因而可以使用自己的独立符号名集。与包的引用结合,可以用单引号(')操作符来定位类中的变量,类中成员的定位形式如:$class'$member。在Perl5中,可用双冒号替代单引号来获得引用,如:$class'$member与$class::$member相同。

    三、创建类

      package Cocoa;

      #
      # Put "require" statements in for all required,imported packages
      #

      #
      # Just add code here
      #

      接下来,我们往包里添加方法使之成为一个类。第一个需添加的方法是new(),它是创建对象时必须被调用的,new()方法是对象的构造函数。

    四、构造函数

      sub new {
          my $this = {}; # Create an anonymous hash, and #self points to it.
          bless $this; # Connect the hash to the package Cocoa.
          return $this; # Return the reference to the hash.
      }

      1 #!/usr/bin/perl
      2 push (@INC,'pwd');
      3 use Cocoa;
      4 $cup = new Cocoa;

      

      ps,

      1. 一定要在构造函数中初始化变量;

      2. 一定要用my函数在方法中创建变量;

      3. 一定不要在方法中使用local,除非真的想吧变量传递给其他子程序;

      4. 一定不要在类模块中使用全局变量。

    五、方法

      Perl类的方法只不过是一个Perl子程序而已,也即通常所说的成员函数。Perl的方法定义不提供任何特殊语法,但规定方法的第一个参数为对象或者其被引用的包。Perl有两种方法,静态方法以及虚方法。

      静态方法的第一个参数为类名,虚方法的第一个参数为对象的引用。

    六、方法的输出

      如果你现在想引用Cocoa.pm包,将会得到编译错误说未找到方法,这是因为Cocoa.pm的方法还没有输出。输出方法需要Exporter模块,在包的开始部分加上下列两行:
        require Exporter;
        @ISA = qw (Exporter);
        这两行包含上Exporter.pm模块,并把Exporter类名加入@ISA数组以供查找。接下来把你自己的类方法列在@EXPORT数组中就可以了。例如想输出方法closeMain和declareMain,语句如下:
        @EXPORT = qw (declareMain , closeMain);
        Perl类的继承是通过@ISA数组实现的。@ISA数组不需要在任何包中定义,然而,一旦它被定义,Perl就把它看作目录名的特殊数组。它与@INC数组类似,@INC是包含文件的寻找路径。@ISA数组含有类(包)名,当一个方法在当前包中未找到时就到@ISA中的包去寻找。@ISA中还含有当前类继承的基类名。
        类中调用的所有方法必须属于同一个类或@ISA数组定义的基类。如果一个方法在@ISA数组中未找到,Perl就到AUTOLOAD()子程序中寻找,这个可选的子程序在当前包中用sub定义。若使用AUTOLOAD子程序,必须用use Autoload;语句调用autoload.pm包。AUTOLOAD子程序尝试从已安装的Perl库中装载调用的方法。如果AUTOLOAD也失败了,Perl再到UNIVERSAL类做最后一次尝试,如果仍失败,Perl就生成关于该无法解析函数的错误。

    七、方法的调用

      调用一个对象的方法有两种,一是通过该对象的引用(虚方法),二是直接使用类名(静态方法)。当然该方法必须已经被输出。

    package Cocoa;
    require Exporter;
    @ISA = qw(Exporter);
    @EXPORT = qw(setImports, declareMain, closeMain);
    #
    # This routine creates the references for imports in Java functions
    #
    sub setImports{
      my $class = shift @_;
      my @names = @_;
      foreach (@names) {
        print "import " . $_ . "; ";
      } 
    }
    #
    # This routine declares the main function in a Java script
    #
    sub declareMain{
      my $class = shift @_;
      my ( $name, $extends, $implements) = @_;
      print " public class $name";
      if ($extends) {
        print " extends " . $extends;
      }
      if ($implements) {
        print " implements " . $implements;
      }
      print " { ";
    }
    #
    # This routine declares the main function in a Java script
    #
    sub closeMain{
      print "} ";
    }
    #
    # This subroutine creates the header for the file.
    #
    sub new {
      my $this = {};
      print " /* ** Created by Cocoa.pm ** Use at own risk */ ";
      bless $this;
      return $this;
    }

    1;

        现在,我们写一个简单的Perl脚本来使用该类的方法,下面是创建一个Java applet源代码骨架的脚本代码:

    #!/usr/bin/perl
    use Cocoa;
    $cup = new Cocoa;
    $cup->setImports( 'java.io.InputStream', 'java.net.*');
    $cup->declareMain( "Msg" , "java.applet.Applet", "Runnable");
    $cup->closeMain();

    八、重载

      有时需要制定使用哪个类的方法,如两个不同的类有同名方法的时候。假设类Espresso和Qava都定义了方法grind,可以用::操作符指定使用Qava的方法:
        $mess = Qava::grind("whole","lotta","bags");
        Qava::grind($mess, "whole","lotta","bags");
        可以根据程序的运行情况来选择使用哪个类的方法,这可以通过使用符号引用去调用来实现:
        $method = $local ? "Qava::" : "Espresso::";
        $cup->{$method}grind(@args);

    九、析构函数

      Perl跟踪对象的链接数目,当某对象的最后一个应用释放到内存池的时候,该对象就自动销毁。对象的西沟发生在代码停止后,脚本将要结束时。对于全局变量而言,析构发生在最后一行代码运行之后。

      如果你想在对象被释放之前获取控制权,可以定义DESTROY()方法。DESTROY()在对象将释放前被调用,使你可以做一些清理工作。DESTROY()函数不自动调用其它DESTROY()函数,Perl不做内置的析构工作。如果构造函数从基类多次bless,DESTROY()可能需要调用其它类的DESTROY()函数。当一个对象被释放时,其内含的所有对象引用自动释放、销毁。
        一般来说,不需要定义DESTROY()函数,如果需要,其形式如下:

    sub DESTROY {
    #
    # Add code here.
    #
    }

      因为多种目的,Perl使用了简单的、基于引用的垃圾回收系统。任何对象的引用数目必须大于0,否则该对象的内存就会被释放。当程序退出时,Perl的一个彻底的查找并销毁函数进行垃圾回收,进程中的一切被简单地删除。在UNIX类的系统中,这是多余的,但在内嵌式系统或者多线程环境中这确实是必要的。

    十、继承

      

    十一、子类方法的继承

    十二、Perl类和对象的一些注释

      OOP的最大好处就是代码重用。OOP用数据封装来隐藏一些复杂的代码,Perl的包和模块通过my函数提供数据封装功能,但Perl并不保证之类一定不会直接访问基类的变量,这确实减少了数据封装的好处,虽然这种动作是可以做到的,但却是一个很坏的的编程风格。

      1. 一定要通过方法来访问类变量;  

      2. 一定不要从模块外直接访问类变量。

      当编写包时,应该保证方法所需的条件已具备或者通过参数传递给它。在包内部,应保证对全局变量的访问只用通过方法传递的引用来访问。对于方法要使用的静态或者全局数据,应该在基类中使用local()定义,自雷通过调用基类来获取。有时,子类可能需要改变这种数据,这时,基类可能就不知道怎样去寻找新的数据,因此,这时最好定义对该数据的引用,子类和基类都通过引用来改变该数据。

  • 相关阅读:
    sql server将多条数据,通过指定列拼接成一条数据
    sql server游标demo
    C# 使用HttpCilent请求接口,传递表单数据(可上传图片)
    sql server 把日期时间类型 转为字符串
    Http请求失败,获取返回状态码和消息
    url
    解决基础连接已经关闭: 未能为 SSL/TLS 安全通道建立信任关系。
    MD5 加密
    C# 读取txt文件内容
    微信小程序 图片转为base64
  • 原文地址:https://www.cnblogs.com/yiyi-xuechen/p/4422480.html
Copyright © 2020-2023  润新知