【问题标题】:How can I set a static variable that can be accessed by all subclasses of the same base class (Perl/Moose)?如何设置一个可以被同一基类(Perl/Moose)的所有子类访问的静态变量?
【发布时间】:2011-11-27 01:55:09
【问题描述】:

由于 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 模块安装 =/ 所以 Moose - 现在只有解决方案有帮助!)

【问题讨论】:

  • 刚刚更新了我的答案 =) 因为我知道你仍然很活跃。

标签: perl oop static moose


【解决方案1】:

更新

现在有一个很多更好的方法来做到这一点,使用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();

此外,是否有描述这种行为的设计模式?

是的。它被称为单例。单例模式是一种模式,多个启动(调用->new)将返回相同的对象。您可以这样做,也可以将变量存储在类之外。 Moose 提供了一个允许您轻松创建单例的层(认为这两种方法都不是特别难):模块MooseX::Singleton。 Moose 还允许您delegate to another object by using an accessor

这里我们使用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 )]
);

【讨论】:

  • +1 for Test::More,我以前没听说过这个,但我很高兴我听说过。我也无法在我的系统上安装 MooseX。你有这个解决方案的 Moose 版本吗?
  • @JackManey 谢谢你的链接,我会再试一次!我仍然希望看到 Moose 解决方案 =]
  • 我同意 JackManey 的观点,local::lib 的想法更好。没有 CPAN 会让 perl 变得难以忍受。
猜你喜欢
  • 1970-01-01
  • 2014-06-06
  • 1970-01-01
  • 1970-01-01
  • 2012-09-06
  • 2013-04-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多