强制执行来自元模型的单个实例 [英] Enforcing single instances from the metamodel

查看:0
本文介绍了强制执行来自元模型的单个实例的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我知道从类级别确保单个实例要容易得多,而且Jonathan Stowe提供了出色的Staticish模块,它通过使用角色来实现相同的功能,但我只想尝试更好地理解如何处理class higher order working,主要是为了FOSDEM演讲。我可以想出几种在元模型级别执行操作的方法,但最终我想出了以下方法:

my class MetamodelX::Singleton is Metamodel::ClassHOW {

    my instance = Mu;

    method compose(Mu 	ype) {
        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编写)

主要原理是试图包装构建子方法,或者以某种方式尝试创建对象的新实例。但是,此操作(以及与原始版本相近的BUILDBUILDALL)失败,错误为:

No such method 'wrap' for invocant of type 'Any'.  Did you mean any of
these: 'Map', 'WHAT', 'grep', 'map'?
因此,很明显,我不了解它们的作用,也不了解整个How概念。那么,你知道这里可能失败的是什么吗,或者有什么其他方法可以在元模型级别覆盖对象的构建,以便能够按预期执行操作?

推荐答案

此尝试中存在一些误解。

  1. 每个类型都有一个元类的实例。因此,如果我们希望只允许给定类型实例化一次,正确的作用域是元类中的属性,而不是mymy表示无论我们创建哪种类型,都只有一个全局对象。
  2. compose方法在子类化ClassHOW时,应该始终回调到基本compose方法(这可以使用callsame来完成)。否则,将不会编写该类。
  3. method_table方法返回此精确类型的方法表。但是,大多数类都没有new方法。相反,它们将继承默认设置。然而,如果我们包装,我们将产生非常全球性的效果。
虽然new重写以将接口更改为构造是相对常见的,但new方法--new在执行任何映射工作后调用--不是我们期望语言用户重写的东西。因此,我们可以继续的一种方法是尝试安装一个执行所需逻辑的bless方法。(我们也可以使用new,但实际上我们需要检查这个类中是否有一个,如果有,则包装它,如果没有,则添加一个默认的副本,如果没有,则包装,这会稍微费力一些。)

这里有一个有效的解决方案:

my class MetamodelX::Singleton is Metamodel::ClassHOW {
    has $!instance;

    method compose(Mu 	ype) {
        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;
    }
}
请注意,我们不能在为bless添加的代码中使用callsame,因为它实际上不是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

这篇关于强制执行来自元模型的单个实例的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆