由于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解决方案现在有帮助!)
最佳答案
更新
现在有一种更好的方法,使用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提供了一个允许您轻松创建Singleton的层(无论哪种方式都没有特别困难):模块MooseX::Singleton。驼鹿还允许您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 )]
);