编写子函数并将其全部放在一个文件中与编写包有什么区别?就 Perl 而言,面向对象是否比面向过程更好?
基本上是在寻找 OO 比程序更好的场景示例。
谢谢!
编写子函数并将其全部放在一个文件中与编写包有什么区别?就 Perl 而言,面向对象是否比面向过程更好?
基本上是在寻找 OO 比程序更好的场景示例。
谢谢!
首先澄清一下,程序和 OO 之间的区别与将所有代码放在一个文件中与将其放在单独的模块中的区别不同。您可以拥有单独的模块,这些模块充满了您在程序上调用的功能。
使用模块、OO 或过程的优势在于代码将被重用,或者它只是一个大型代码库。如果您的 CMS 包含 10 个不同的 CGI 脚本,它们都执行若干相同的事情,例如验证用户会话,那么将代码放入单独的模块中而不是在每个 CGI 中重写它是有意义的。如果它是特定于该脚本的 20 行函数,则将其保留在同一个文件中。
是使用 OO 还是程序化取决于您在做什么。大多数人现在大部分时间都会偏爱OO。我同意他们的观点,因为我认为它可以帮助您从逻辑上思考您的代码,并以一种易于管理和稍后更新的合理方式将事物组合在一起。
我喜欢将尽可能多的代码放入模块中。模块的好处是您可以使用 Perl 的测试工具(prove 和 Test::More)轻松编写和管理单元测试。因此,如果几乎所有代码都在模块中,那么几乎所有代码都是可测试的。
当我编写脚本时,我喜欢有一个瘦包装器来解析我的脚本中的配置和命令行选项(可能使用像 Config::Any 或 Getopt::Long 这样的模块)。该脚本还包含一个usage
子例程。然后我添加一个main
子程序。 main
很简单:
sub main {
my $cfg = shift;
my @collected_data;
for my $file ( @{ $cfg->{files} ) {
eval {
my $fh = get_handle_from_file($file);
my $xyz_data = parse_xyz_data( $fh );
push @collected_data, extract_data( $xyz_data, $cfg->{filter} );
1;
} or do {
my $e = $@;
$e = "an unknown error occurred" unless defined $e;
warn "Error parsing '$file': $e\n";
};
}
my %summary_data = summarize_data( @collected_data );
write_summary( $cfg->{summary_target} );
return;
}
几乎所有的支持子程序都存在于一个或多个模块中。
OOP 是一种将数据和行为关联起来的好方法。这可以使代码更具可读性并减少混乱。
$foo->eat_something( $sandwich )
比以下更容易理解:
eat_something( $sandwich, $likes_salty, $likes_sour, $likes_sweet, $likes_spicy );
所有额外的废话都捆绑在方便的$foo
对象属性中,并且不会弄乱子调用。
当然你可以这样做:
eat_something( $foo, $sandwich )
其中 $foo 只是口味偏好的普通哈希。无论如何,这本质上就是 Perl OO 所做的。调用者(对象或类名)作为第一个参数传递给每个方法。你确实失去了方便的命名空间、继承和动态方法调用。在这三种成本中,最容易错过的就是方便的命名空间。IMO,继承被高估了,应该很少使用。动态方法调用很方便,原因与调度表很方便的原因相同。
在 OO Perl 中没有什么是你不能在过程 Perl 中做的。但是,OO 使某些事情变得非常方便。
让我以 OO 风格重写我的神话脚本来结束(我会在 OO 上有点过火,只是为了说明):
子主 { 我的 $cfg = 班次;
my $cd = Data::Collection->new();
for my $file ( $cfg->files ) {
eval {
# skip the step of creating a handle first. The parsing object
# can take a file and get a handle or could be passed a handle.
my $xyz_parser = File::XYZ::Parse->new( file => $file );
# The parser returns an XYZ::Data object
my $xyz_data = $xyz_parser->parse;
$cd->add_data( $xyz_data->extract_data( $cfg->filter );
1;
} or do {
my $e = $@;
$e = "an unknown error occurred" unless defined $e;
warn "Error parsing '$file': $e\n";
};
}
# Skip the step of separate summarization, since the cd object can check if
# the summary has been done, and if not generate and cache it as needed.
$cd->write_summary( $cfg->summary_target );
return;
}