Как определить частные или внутренние методы в объектно-ориентированном Perl? - PullRequest
8 голосов
/ 14 ноября 2009

Я использую объекты «изнутри» Дамиана Конвея, как описано в его замечательной книге Perl Best Practices , для создания объектно-ориентированного интерфейса с системой безопасности на моем клиенте.Я сталкиваюсь с необходимостью использования внутренних вспомогательных методов в моем модуле, которые я обычно обозначаю как "_some_method".Однако это, кажется, нарушает инкапсуляцию, так как они могут быть вызваны напрямую через имя пакета.Есть ли способ сделать эти методы действительно частными?Например,

use SOD::MyOOInterface;

my $instance1 = SOD::MyOOInterface->new();
$instance1->_some_method;  #this produces an error: 
SOD::MyOOInterface::_some_method;   # this results in a 
                                    # successful method call 

Очевидно, я не хочу, чтобы прямой вызов _some_method завершился успешно.Есть ли способ гарантировать это?

Ответы [ 4 ]

11 голосов
/ 14 ноября 2009
package Foo;

## declare inside-out hashes here:

my %attr_a;
my %attr_b;

## declare private methods here

my $private_1 = sub {
  my $self = shift;
  # can use $attr_a{$self} here...
  ...
};

my $private_2 = sub {
  my $self = shift;
  ... 
};

## public methods here

sub new { ... }

sub public_1 {
  my $self = shift;
  # can access attributes here
  # can call private methods too, with slightly odd syntax:
  my $result = $self->$private_1(@args);
  ...
}

1;
6 голосов
/ 14 ноября 2009

Не используйте PBP для объектных практик. Это очень старый. Фактически, теперь лучшие практики в отношении Perl и объектов можно найти в Moose , почти обязательном для Perl.

Короче говоря, то, как Perl размывает пространства имен и классы, большинство методов можно вызывать статически в классе. Это не плохо, просто не документируйте это. На самом деле нет причин запечатлевать методы в экземпляре. Отсутствие частных методов раздражает, но соглашение о том, чтобы не полагаться на недокументированные методы, настолько сильно, что этого достаточно для нашего сообщества.

Черта - это фактически роль (не допускающая реализации), которая может быть скомпилирована в объект во время выполнения. Это еще больше затеняет происхождение методов от вашего обычного пользователя (потому что они не будут в исходном классе), но это требует затрат времени выполнения. См. MooseX :: Traits для получения дополнительной информации о чертах.

Подчёркивающее подчеркивание является отличным соглашением о том, что этот метод является приватным для глаз.

В качестве последнего замечания, если вы действительно хотите решить эту проблему, вы можете создать анонимный класс с помощью этих методов, используя Class :: MOP :: Class-> create_anon_class ()

6 голосов
/ 14 ноября 2009

Вроде. Вы не можете скрыть подпрограмму, которая установлена ​​в таблице символов, но вы можете использовать лексическую переменную для хранения ссылки на анонимную подпрограмму:

package SOD::MyOOInterface;

my $some_method = sub { ... }

$some_method->();

Поскольку $some_method виден только в файле, реализующем класс, подпрограмма не может быть вызвана извне. Недостатком является то, что он не может быть вызван как метод, он должен быть вызван как функция. Если вы хотите использовать его как метод, вам придется явно передать ссылку на объект:

$some_method->($obj, @args);
1 голос
/ 14 ноября 2009

То, как я с этим справляюсь, это добавить что-то вроде этого в начале метода:

my $self = shift;
croak "Instance method called on class" unless ref $self;

Это никоим образом не является истинной инкапсуляцией, но это означает, что кто-то, вызывающий вас через пакет, должен будет передать экземпляр объекта в качестве первого аргумента. Вообще с Perl я не вижу особой смысла защищать от злонамеренных пользователей моего API - это просто помогает мне ловить ситуации, когда я случайно пытаюсь вызвать метод как метод класса (что происходит чаще, чем я хотел бы) признать).

Лично я думаю, что соглашение о подчеркивании + четкое документирование метода как частного (или не документирование его вообще, чтобы он не отображался в POD) достаточно для реального использования. Это также, как это работает в Python. Это часть языковой философии , не ограничивающей пользователей.

Модуль Perl предпочел бы, чтобы вы не входили в его гостиную, потому что вас не пригласили, а не потому, что у него есть дробовик ...

...