Chinaunix首页 | 论坛 | 博客
  • 博客访问: 43959
  • 博文数量: 7
  • 博客积分: 173
  • 博客等级: 入伍新兵
  • 技术积分: 115
  • 用 户 组: 普通用户
  • 注册时间: 2012-08-06 18:31
文章分类
文章存档

2012年(7)

我的朋友

分类: Python/Ruby

2012-08-10 11:22:02

类(class) vs. 包(package) vs. 模块(Module)


  • 在Perl 5语言里没有正式的有关"类"的定义。类只是一个面对对象编程(Object Oriented Programming)的概念。


  • 包是Perl整合资源(函数、变量等)的一种方式。这些资源通常有着某种意义上的关联(也可以完全无关,perl不会限制你这样做。)
  • 其命名空间的定义也不需要与目录/文件结构相匹配。(包可以定义于脚本内部,只限于该脚本调用。)
  • 包的内容不非得是面对对象的。

模块

  • 模块无非是一个外向(可公共调用)的包。
  • 所以其命名空间的定义有与之相匹配的目录/文件结构。(如果你的模块是Foo::Bar::Baz,它需要有对应的目录/文件结构 "Foo/Bar/Baz.pm"。)
  • 同包一样,模块的内容不非得是面对对象的。

Perl OO

Perl是一门自由、宽容的语言。一些规矩或范例不会强加给使用者,而是在使用者需要时随心调用。在面对对象的编程上亦不例外。

由于perl没有关于“类”的正式定义,就需要一种方式来声明一个对象和一个包的关联,从而使这个对象“进入”这个包的命名空间。bless()函数可以帮你完成这个操作。

bless $object, __PACKAGE__;

Perl的“类”函数与普通函数在功能上完全等同。只不过类函数的第一个参数必须是调用它的对象,即箭头运算符 "->"左边的那个值。也就是说,

  1. Class->method( @arg ) 等同于 Class::method( 'Class', @arg )
  2. $obj->method( @arg )  等同于 (ref $object)::method( $obj, @arg ) ***
所以写构造函数时通常如下,注意bless语句并不是直接把对象bless成$class,为什么呢?

  1. package Foo;

  2. sub new
  3. {
  4.     my $class = shift;
  5.     my %this;
  6.     ...
  1.     bless \%this, ref $class || $class;
  2. }
其实原因在上面已经说明白了。(看上面 *** )这是因为类函数不仅可以通过类(包)的名字"Foo"来调用,即
  1. my $foo = Foo->new();
也还可以通过一个"Foo"对象来调用,即
  1. my $bar = $foo->new();
所以bless时要判断调用类函数的是类还是类对象,如果是通过类对象调用的,就bless成调用对象的那个类(ref $class);如果是通过类的名字调用的,直接bless成类就好了!

下面举个矩阵应用小例子(涉及到包和OO)。

点击(此处)折叠或打开

  1. #!/usr/bin/perl -w

  2. use strict;

  3. my $matrix = Matrix->new( [ 1, 2, 3 ], [ 4, 5, 6 ], [ 7, 8, 9] );

  4. print join "\n",
  5.     'before => ', $matrix->string,
  6.     'after => ', $matrix->transpose->string, "\n";

  7. package Matrix;

  8. sub new
  9. {
  10.     my ( $class, @this ) = @_;
  11.     bless \@this, ref $class || $class;
  12. }

  13. sub transpose
  14. {
  15.     my $this = shift @_;
  16.     my $column = @{ $this->[0] };

  17.     for ( my $i = 0; $i < @$this; $i ++ )
  18.     {
  19.         for ( my $j = $i; $j < $column; $j ++ )
  20.         {
  21.             ( $this->[$i][$j], $this->[$j][$i] ) =
  22.             ( $this->[$j][$i], $this->[$i][$j] );
  23.         }
  24.     }

  25.     return $this;
  26. }

  27. sub string
  28. {
  29.     my $this = shift;
  30.     join "\n", map { join ' ', @$_ } @$this;
  31. }

  32. sub size
  33. {
  34.     my $this = shift;
  35.     my $row = @$this;
  36.     my $col = @{ $this->[0] };

  37.     return wantarray ? ( $row, $col ) : [ $row, $col ];
  38. }

  39. sub row
  40. {
  41.     my ( $this, $row ) = @_;
  42.     my $size = @$this;

  43.     return undef if $row >= $size || $row < -$size;
  44.     my @row = @{ $this->[$row] };
  45.     return wantarray ? @row : \@row;
  46. }

  47. sub col
  48. {
  49.     my ( $this, $col ) = @_;
  50.     my $size = @{ $this->[0] };
  51.    
  52.     return undef if $col >= $size || $col < -$size;
  53.     my @col = map { $_->[$col] } @$this;
  54.     return wantarray ? @col : \@col;
  55. }

  56. sub copy
  57. {
  58.     my $this = shift;
  59.     my @that = map { [ @$_ ] } @$this;

  60.     bless \@that, ref $this;
  61. }

  62. sub value
  63. {
  64.     my ( $this, $i, $j, $x ) = @_;
  65.     my ( $row, $col ) = $this->size();

  66.     return $i >= $row || $i < -$row || $j >= $col || $j < - $col ? undef
  67.         : defined $x ? ( $this->[$i][$j] = $x ) : $this->[$i][$j];
  68. }

  69. sub get { value( splice @_, 0, 3 ) }

  70. sub set { value( splice @_, 0, 4 ) }

  71. sub dimension { size( @_ ) }

  72. sub column { col( @_ ) }

  73. sub clone { copy( @_ ) }

  74. 1;

注意到这个package的最后一行。这是因为perl要求包的评价必须为真,所以最后一行是

  1. 1;


阅读(5632) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~