如何设置可以由同一基类(Perl/Moose)的所有子类访问的静态变量? [英] How can I set a static variable that can be accessed by all subclasses of the same base class (Perl/Moose)?
问题描述
由于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唯一的解决方案目前有帮助!)
UPDATE
现在有一种很多更好的方法,请使用 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提供了一个图层,可以让您轻松创建Singleton(无论哪种方式都没有特别困难):模块使用访问器代理到另一个对象.>
在这里,我们使用 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 )]
);
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!)
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 )]
);
这篇关于如何设置可以由同一基类(Perl/Moose)的所有子类访问的静态变量?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!