Как мне установить статическую переменную, к которой могут обращаться все подклассы одного и того же базового класса (Perl / Moose)? - PullRequest
7 голосов
/ 28 сентября 2011

Поскольку Perl / Moose всегда вызывает функцию BUILD базового класса перед вызовом функции BUILD подкласса, каждый раз при создании экземпляра подкласса создается новый экземпляр базового класса.

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

Я пытаюсь создать переменную, которая динамически включает или отключает определенные функции функции, определенной во время выполнения в базовом классе, но доступной из подклассов.

Так что, если я сделаю что-то вроде

my obj = My::childObject_1->new( 'use_my_var' => 1 );

это также будет верно для

my obj2 = My::childObject_2->new();
my obj3 = My::childObject_3->new();

без необходимости конкретно определять эту переменную. Если только

my obj4 = My::childObject_2->new( use_my_var' => 0 ); 

в этом случае с этого момента оно будет ложным для всех подклассов, потому что все они

extends My::BaseObject

Кроме того, существует ли шаблон проектирования, который описывает это поведение?

(Примечание: я нахожусь в общей системе, поэтому я не могу установить MooseX - или, по крайней мере, я не смог выяснить, как настроить локальные установки модулей PERL5LIB в моем каталоге пользователя = / so Moose только решение помогает!)

1 Ответ

10 голосов
/ 28 сентября 2011

ОБНОВЛЕНИЕ

Теперь есть намного лучший способ сделать это, используйте MooseX :: ClassAttribute

Тогда просто используйте class_hasвместо has для методов, которые вы хотите использовать совместно со всеми экземплярами.

package My::Class;

use Moose;
use MooseX::ClassAttribute;

class_has 'Cache' =>
    ( is      => 'rw',
      isa     => 'HashRef',
      default => sub { {} },
    );

__PACKAGE__->meta()->make_immutable();

OLD

Кроме того, существует ли шаблон проектирования, который описывает это поведение?

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

. Здесь мы используем MooseX :: Singleton и переход к скрытому атрибуту для достижения желаемогоЭффект.

package MySingleton;
use MooseX::Singleton;

has 'foo' => ( is => 'rw', isa => 'Bool', default => 0 );

package ClassA;
use Moose;

has '_my_singleton' => (
  isa => 'MySingleton'
  , is => 'ro'
  , default => sub { MySingleton->new }
  , handles => [qw( foo )]
);


package ClassB;
use Moose;

has '_my_singleton' => (
  isa => 'MySingleton'
  , is => 'ro'
  , default => sub { MySingleton->new }
  , handles => [qw( foo )]
);

package main;
use Test::More tests => 5;

my $class_a = ClassA->new;
my $class_b = ClassA->new;

is( $class_a->foo(0), 0, 'Set A to false' );
is( $class_a->foo, 0, 'A Is false' );
is( $class_b->foo, 0, 'B Is false' );
is( $class_b->foo(1), 1, 'Set B to true' );
is( $class_a->foo, 1, 'A is true' );

Или без MooseX

Пожалуйста, не делайте этого без необходимости.Метод MooseX гораздо приятнее:

package Underclass;
use Moose;

has 'foo' => ( is => 'rw', isa => 'Bool', default => 0 );

package SingletonWrapper;
my $obj;
sub new {
    if ( $obj ) { return $obj; }
    else { $obj = Underclass->new }
}

package ClassA;
use Moose;

has '_my_singleton' => (
    isa => 'Underclass'
    , is => 'ro'
    , default => sub { SingletonWrapper->new }
    , handles => [qw( foo )]
);


package ClassB;
use Moose;

has '_my_singleton' => (
    isa => 'Underclass'
    , is => 'ro'
    , default => sub { SingletonWrapper->new }
    , handles => [qw( foo )]
);
...