Perl 对象化编程的实现

缘由

最近反过头来看Perl,一方面是我的客户厂家用Perl开发了很多东西,另一方面在了解过程中,又复习了Perl语言,并且有了一些心得。记录下来,供大家参考。

我在做一个小程序,就是解析一个文本文件,将其中的内容进行处理,并保存在另一个文件。

背景知识

1. Perl的对象化编程实现

请参考阅读:

O'Reilly - Advanced Perl Programming.pdf - 第7章 [Object-Oriented Programming]

2. 在Perl中如何使用引用

http://www.chinaunix.net/jh/25/504623.html

3. Perl中如何读取文件

Perl cookbook [O'reilly Perl Cookbook.pdf] - 第7章 [File Access]

4. Perl的正则表达式

http://www.chinaunix.net/jh/25/159388.html

具体实现

对象编程是为了解决长期依赖困扰的维护和扩展的工作。如果我们的代码只写一次,以后再也不需要改动,那么也许现代编程模型就不会演化。当然我们知道这是不可能的。世界唯一不变就是变化。

Perl做为一种功能强大的脚本语言在各个方面都有运用(但没有在UI方面使用),但是由于脚本语言的特性,write once的标签一直伴随着它。大家普遍认为它是一种晦涩的并难以维护的程序语言。

其实这方面,大家有一些误解。语言使用跟开发人员的水平和涵养有关系,即便在C#这种良好的高级对象语言的基础上,部分开发人员仍然可以写糟糕的难以读懂的语言结构来。因此,开发人员不仅仅是要学会在高级语言上使用对象编程,并更需要深刻理解对象概念,最终能将这种概念运用到不同的语言中来,使其语言结构,模块化,对象化。

在我刚刚接触Perl的时候,我认为这种语言根本无法写出对象化的语言结构。因此,我对此有诸多抱怨。但随着学习的深入,Perl一样可以使用对象的概念来构件合适和清晰的语言结构。

我把最后测试的代码先贴上来:

use filehandle::filehandler;
use filehandle::catchWorkerId;

print "\nTEST fildehander base class \n\n";
my $filehandler =  filehandler->new("c:\\test2.ini");
print $filehandler->getDealedStrings();

print "\nTEST fildehander sub-class \n\n";
$filehandler = catchWorkerId->new("c:\\test2.ini");
print  $filehandler->getDealedStrings();
$filehandler->exportToFile("C:\\test2_new.ini");

filehandler.PM和catchworkerId.PM是我们重要的两个Module(class)。fileHandler类是父类并完成了一个文件解析的基本动作:

打开文件

每行读取

解析字符串并保存在类的数组变量里面

导出到合适的文件中

这样我们就可以只在子类里面完成需要变动的部分。请看子类代码catchworkId.PM

package catchWorkerId;
@ISA = qw(filehandler);
use strict;
use warnings;


sub convert
{

   my ($self,$linetext) = @_;

  my $pattern = "[a-z0-9]{9}[(]";
  my @a;
  if(@a=($linetext =~/$pattern/gio))
  {
    $a[0]=~s/[(]//g;
    return (1,$a[0]);
   }

return (0,"");
}

1;

代码说明

子类代码只是完成一个方法convert,它的输入是一个$linetext 字符串标量,我们进行正则表达式的判断,如果满足匹配则返回true+替换后的$linetext,如果不满足就返回false+空字符串。

如果在C#这类对象强类型语言中我们可以这样定义:

bool convert(string linetext, out string convetedlinetext)
{
 //implemenet code
}

由于Perl是一种解释性非类型语言,因此我们需要变通的实现这一功能。 所以,如何在新的概念情况下,用旧有语言来实现特定的功能,就需要开发人员的创新能力,这些东西不会在教程上讲述,而需要开发人员自己的摸索。

你看通过类的继承的方式,我们在子类只定义函数就完成我们预设目标。需要注意这一句:

@ISA = qw(filehandler);

它的意思是,引入filehandler.PM的函数,首先在catchWorkerId中查找调用函数,如果没有找到,会继续在filehandler.pm中查找。通过这种方式,我们完成了变相实现了类的继承

这里给出父类的实现:filehandler.PM

package filehandler;
use strict;
use warnings;

#new
sub new
{
  my($class, $filename) = @_;
  my $self ={
    _filename =>$filename
    };
  my @ss;
  $self->{_dealedStringArray}= \@ss;

  return bless($self,$class);
}

#really open file
sub getDealedStrings
{
  my($self) = @_;
  open (FILEHANDLE,$self->{_filename})|| die("can't open file: $self->{_filename}");
  #start to deal string line by line!
while(<FILEHANDLE>)
{
 $self->handleLine($_);
}
close (FILEHANDLE);
return  @{$self->{_dealedStringArray}} ;
}

#deal string line by line
sub handleLine
{
  my ($self,$linetext) = @_;
  my @result = $self->convert($linetext);
  if($result[0]==1)
  {

  $self->_addstring($result[1]);
  }


}
#You can write a override function in sub class
sub convert
{
  my ($self,$old) = @_;
  $old = "CONVERTED STRING:" .$old;
  return (1,$old);
}

#add the dealed string into a array.
sub _addstring
{
  my ($self,$linetext) = @_;

  my @a =@{ $self->{_dealedStringArray}};

  push(@a, $linetext."\n");
  @{$self->{_dealedStringArray}} = @a;

}

#output converted file
sub exportToFile
{
  my($self,$newFileName) = @_;
  open FILEHANDLE ,">$newFileName" || die("can't create file : $newFileName");
  for(my $i=0;$i<@{$self->{_dealedStringArray}};$i++)
  {
    print FILEHANDLE "${$self->{_dealedStringArray}}[$i]";
  }

  close FILEHANDLE;
}
1;

这里不在具体讲Perl 对象编程的概念,大家可以变参考背景知识里面推荐的O'Reilly - Advanced Perl Programming,边看本实例,一定会有所心得。