如何设置一个可由同一基类(Perl/Moose)的所有子类访问的静态变量?

发布于 2024-12-07 01:46:51 字数 749 浏览 1 评论 0原文

由于 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 的解决方案暂时有帮助!)

Since Perl/Moose always calls the base class' BUILD function before it calls the subclass BUILD function, there is a new instance of the base class everytime you instantiate a subclass.

How do I go about creating a static variable that can be used by all the subclasses, or alternatively how can I create a static base or abstract class? (does that approach even make sense?)

I'm trying to create a variable that dynamically enables or disables certain features of a function defined at run-time in the base class but accessible from the sub classes.

So if I do something like

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

it will also be true for

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

without having to specifically define that variable. Unless

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

in which case it would from that point be false for all subclasses because they all

extends My::BaseObject

Additionally, is there a design pattern that describes this behavior?

(Note: I'm on a shared system so I can't install MooseX -- or at least I haven't been able to figure out how to setup local PERL5LIB installs of modules in my user directory =/ so Moose-only solution helps for now!)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

诺曦 2024-12-14 01:46:51

更新

现在有一个更好更好的方法来做到这一点,使用 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 还允许您使用访问器委托给另一个对象

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

UPDATE

Now there is a much better way to do this, use MooseX::ClassAttribute

Then just use class_has rather than has for the methods you want shared with all instances.

package My::Class;

use Moose;
use MooseX::ClassAttribute;

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

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

OLD

Additionally, is there a design pattern that describes this behavior?

Yes. It's called a Singleton. A Singleton is a pattern whereby multiple initiations (calls to ->new) will return the same object. You can either do it like this, or store the variable outside of a class. Moose provides a layer that will permit you to create Singletons easily (thought it isn't particularly hard either way): the module MooseX::Singleton. Moose also permits you to delegate to another object by using an accessor.

Here we use MooseX::Singleton, and delgation to a hidden attribute to achive the desired effect.

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' );

Or, without MooseX

Please don't do this unless required. The MooseX method is much nicer:

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 )]
);
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文