我正在扩展一个模块,我想要一些关于良好实践的技巧.特别是命名空间冲突:它们究竟是什么以及如何避免它们.
扩展时,我是否应该访问SUPER类中的变量并仅通过访问器或对象方法更改其状态?如果没有(或有限)访问者怎么办?我是否"允许"直接访问这些对象变量?
干杯!
最好只通过访问器访问事物,因为这可以防止超类的实现中的更改影响子类.你应该远离任何以下划线开头的东西.那些东西都是私人的.尽量远离任何未记录的内容.依靠这些东西会让你陷入困境.另外,请考虑使用has-a与is-a的关系.
让我们想象一个小部件类.这个类有名称和价格成员(注意,这些都不是特别好的代码,我只是抛出了一个版本而不考虑它的例子):
package Widget;
use strict;
use warnings;
sub new {
my $class = shift;
my %args = @_;
return bless {
price => $args{price} || 0,
name => $args{name} || "unkown",
}, $class;
}
sub price { shift->{price} }
sub name { shift->{name} }
1;
Run Code Online (Sandbox Code Playgroud)
您决定子窗口小部件以添加权重成员:
package Widget::WithWeight;
use strict;
use warnings;
use base 'Widget';
sub new {
my $class = shift;
my %args = @_;
my $self = $class->SUPER::new(%args);
$self->{weight} = $args{weight} || 0;
return bless $self, $class;
}
sub weight { shift->{weight} }
sub price_per_pound {
my $self = shift;
return $self->{price}/$self->{weight};
}
1;
Run Code Online (Sandbox Code Playgroud)
现在想象一下,第一个模块的作者改变了他/她关于如何存储价格的想法.也许它被存储为一个浮点数,作者意识到将它存储为整数个便士会更好:
package Widget;
use strict;
use warnings;
sub new {
my $class = shift;
my %args = @_;
if ($args{price}) {
$args{price} =~ s/[.]//;
}
return bless {
price => $args{price} || "000",
name => $args{name} || "unkown",
}, $class;
}
sub price {
my $self = shift;
my $price = $self->{price};
substr($price, -2, 0) = ".";
return $price;
}
sub name { shift->{name} }
1;
Run Code Online (Sandbox Code Playgroud)
突然间,您的测试将开始失败,但如果您使用了price访问器,那么您将完全不受此更改的影响.