Как мне получить доступ к данным экземпляра в подклассе Perl? - PullRequest
1 голос
/ 04 августа 2009

Я расширяю модуль и хочу получить несколько советов по передовой практике. Особенно конфликты пространства имен: что это такое и как их избежать.

При расширении не должен ли я обращаться к переменным в классе SUPER и изменять его состояние только через методы доступа или методы объекта? Что делать, если нет (или ограничено) средств доступа? Разрешено ли мне напрямую обращаться к этим переменным объекта?

Ура! * * 1005

Ответы [ 2 ]

6 голосов
/ 04 августа 2009

Лучше всего получить доступ к вещам только через средства доступа, потому что это предотвращает изменения в реализации суперкласса, влияющие на подклассы. Вы должны держаться подальше от всего, что начинается с нижней планки. Эти вещи являются частными для класса. Старайтесь держаться подальше от всего, что не задокументировано. Полагаясь на эти вещи, вы попадете в беду. Кроме того, рассмотрите возможность использования отношения «есть против».

Давайте представим класс виджетов. У этого класса есть члены 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, вы были бы изолированы от этого изменения.

1 голос
/ 04 августа 2009

Конфликты пространства имен могут возникать, если вы наследуете из двух модулей в один, и оба они предоставляют (экспортируют) одну и ту же подпрограмму.

Я предлагаю вам взглянуть на Moose, расширение для Perl, которое предоставляет вам классы и роли. Вы можете избежать многих конфликтов, если используете роли. Смотри http://www.iinteractive.com/moose/

Moose также создает автоматические средства доступа к переменным класса, что делает его более безопасным для доступа к ним из наследующих классов.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...