码迷,mamicode.com
首页 > 其他好文 > 详细

Perl中的面向对象编程

时间:2015-04-13 18:19:27      阅读:124      评论:0      收藏:0      [点我收藏+]

标签:

一、模块简介

  模块(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 " . $_ . ";\n";
  } 
}
#
# This routine declares the main function in a Java script
#
sub declareMain{
  my $class = shift @_;
  my ( $name, $extends, $implements) = @_;
  print "\n public class $name";
  if ($extends) {
    print " extends " . $extends;
  }
  if ($implements) {
    print " implements " . $implements;
  }
  print " { \n";
}
#
# This routine declares the main function in a Java script
#
sub closeMain{
  print "} \n";
}
#
# This subroutine creates the header for the file.
#
sub new {
  my $this = {};
  print "\n /* \n ** Created by Cocoa.pm \n ** Use at own risk \n */ \n";
  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()定义,自雷通过调用基类来获取。有时,子类可能需要改变这种数据,这时,基类可能就不知道怎样去寻找新的数据,因此,这时最好定义对该数据的引用,子类和基类都通过引用来改变该数据。

Perl中的面向对象编程

标签:

原文地址:http://www.cnblogs.com/yiyi-xuechen/p/4422480.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!