我知道从类级别确保单个实例要容易得多,而且有很好的StaticishJonathan Stowe 的模块通过使用角色来执行相同的操作,但我只是想尝试更好地理解如何阶级高阶工作可以处理,主要是针对FOSDEM的讲。我可以想到在元模型级别上执行的几种方法,但最终我想到的是:
my class MetamodelX::Singleton is Metamodel::ClassHOW {
my \instance = Mu;
method compose(Mu \type) {
my &callsame := CORE::<&callsame>; # Workaround for RT #127858
self.method_table(type)<new>.wrap: -> \SELF, | {
unless instance.defined { instance = SELF };
callsame();
};
}
}
my package EXPORTHOW {
package DECLARE {
constant singleton = MetamodelX::Singleton;
}
}
主要是从OO::Monitors代码,据我所知,由 JJ Atria 和 Jonathan Worthington 编写)
主要原理是尝试包装构建子方法,或者以某种方式尝试创建对象的新实例。然而,这(以及与BUILD
and BUILDALL
,接近原始),失败并显示:
No such method 'wrap' for invocant of type 'Any'. Did you mean any of
these: 'Map', 'WHAT', 'grep', 'map'?
很明显,我不明白它们的作用,或者整个如何概念。那么,你知道这里可能会失败吗,或者有任何其他方法可以在元模型级别覆盖对象的构建,以便能够按预期进行吗?
这次尝试存在一些误解。
- 每种类型都有一个元类实例。因此,如果我们希望允许给定类型仅实例化一次,则正确的作用域是元类中的属性,而不是
my
. A my
意味着无论我们创建哪种类型,都有一个全局对象。
- The
compose
方法,当子类化时ClassHOW
,应始终回拨至基地compose
方法(可以使用callsame
)。否则,班级将无法组成。
- The
method_table
方法返回此方法的方法表exact类型。然而,大多数课程都没有new
方法。相反,他们将继承默认值。如果我们包裹that然而,我们将会产生非常全球性的影响。
While new
重写以更改构造接口是相对常见的,bless
方法 - 其中new
完成任何映射工作后的调用 - 不是我们期望语言用户覆盖的东西。所以我们可以继续的一种方法是尝试安装bless
执行所需逻辑的方法。 (我们也可以与new
,但实际上我们需要检查此类中是否有一个,如果有则将其包装,然后添加默认副本的副本,如果没有则将其包装,这需要更多的努力。)
这是一个有效的解决方案:
my class MetamodelX::Singleton is Metamodel::ClassHOW {
has $!instance;
method compose(Mu \type) {
self.add_method(type, 'bless', -> \SELF, |c {
without $!instance {
$!instance := SELF.Mu::bless(|c);
}
$!instance
});
callsame();
}
}
my package EXPORTHOW {
package DECLARE {
constant singleton = MetamodelX::Singleton;
}
}
请注意,我们不能使用callsame
在我们添加的代码内部bless
因为它实际上不是一个method
。我们可以将其编写为使用anon method
,但是我们有一个问题,该方法有自己的想法self
,所以我们最终不得不保存元类self
并安排一些其他方式来访问$!instance
.
最后,举一个实际的例子:
use Singleton;
singleton Counter {
has $.x;
method inc() { $!x++ }
}
my $c1 = Counter.new;
$c1.inc;
my $c2 = Counter.new; # Gets same instance as in $c1
$c1.inc;
$c2.inc;
say $c1.x; # 3
say $c2.x; # 3
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)