Лучше всего получить доступ к вещам только через средства доступа, потому что это предотвращает изменения в реализации суперкласса, влияющие на подклассы. Вы должны держаться подальше от всего, что начинается с нижней планки. Эти вещи являются частными для класса. Старайтесь держаться подальше от всего, что не задокументировано. Полагаясь на эти вещи, вы попадете в беду. Кроме того, рассмотрите возможность использования отношения «есть против».
Давайте представим класс виджетов. У этого класса есть члены name и price (обратите внимание, ни один из них не является особенно хорошим кодом, я только что выбросил версию, не думая об этом ради примера):
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;
Вы решили добавить в виджет подкласс для добавления элемента веса:
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;
Теперь представьте, что автор первого модуля передумал о том, как хранить цену. Возможно, он был сохранен как число с плавающей запятой, и автор понял, что лучше хранить его как целое число копеек:
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;
Внезапно ваши тесты начнут давать сбои, но если бы вы использовали аксессор price
, вы были бы изолированы от этого изменения.