Raku OO 能否帮助我避免集成层样板文件

Can Raku OO help me avoid integration layer boilerplate

我非常喜欢 raku OO 的低样板,以至于我有点惊讶我无法摆脱一些集成层样板。

这是我今天的工作(有点打高尔夫球):

class Error {
    has Real  $.absolute;

    method percent( $value ) { 
        "{ ( $!absolute / $value ).abs * 100 }%" 
    }   
}

class Measure {
    has Real  $.value;
    has Error $.error;

    method new( :$value, :$error ) { 
        self.bless( :$value, error => Error.new( absolute => $error ) ) 
    }   
    method error-percent {      # <==== why do I need this intermediary method??
        self.error.percent( $!value )
    }   
}

my $m = Measure.new( value => 10, error => 1 );
say $m.error-percent;   #10%

这适用于...

但是

这并不反映许多错误操作将需要测量值这一事实。那么(如何)Raku 很酷的 OO 模式可以帮助我为错误 class

中的 $.value 添加一个“代理”

我的目标是这样的伪代码:

class Error {
    has Real     $.absolute;
    has Callable &!value-cb;

    method percent {
        "{ ( $!absolute / &!valuecb() ).abs * 100 }%" 
    }   
}

class Measure {
    has Real  $.value;
    has Error $.error;

    method new( :$value, :$error ) { 
        self.bless( :$value, error => Error.new( absolute => $error ), value-cb => &.value() )
    }   
}

my $m = Measure.new( value => 10, error => 1 );
say $m.error.percent;   #10%    <=== note the difference, I just go straight there!

所以我正在摸索的概念是为 $.value 创建某种闭包/函数,并将其推入构造时的错误属性。

我很高兴坚持我所拥有的,如果这被认为是最安全的途径,用 $.value 装饰 Error 对象上的大多数方法。对于我对这个技巧的各种 OOP / 模式术语缺乏了解,我提前表示歉意。

我不是 100% 确定我已经掌握了您要完成的任务,所以我首先解释一下我认为您的目标是什么,然后再说明我将如何解决该问题。如果我解决了错误的问题,请纠正我。

据我了解,您需要一个 Error 对象,它可以按绝对值和 Measure 值的百分比报告错误。但是,您不想采用直接的方法为 Error 对象提供一个记录关联 Measure.value 的字段,因为这会创建您必须保持同步的多个真实来源。因此,您希望 Error 无需单独存储即可访问 Measure.value。这样对吗?

如果是这样,这是一种方法。我不确定 that 是否比您在上面这个打高尔夫球的示例中发布的代码简洁得多,但它避免了对 Measure 上任何修饰方法的需要。 (下面代码中的 Measure.valuerw 这样我就可以展示 Error 如何保持同步,但没有其他原因需要 rw。)

基本思路是给 Error 一个 $!measured-value 字段,然后 bind 该字段给关联的 Measure$.value。这是它的样子:

class Measure {...}
class Error  {
    trusts Measure;
    has Real  $.absolute;
    has Real  $!measured-value;

    method !bind-value(\value) { $!measured-value := value };

    method percent {
        "{ ( $!absolute / $!measured-value ).abs * 100 }%"
    }
}

class Measure {
    has Real  $.value is rw;
    has Error $.error;

    method new(:$value, :$error is copy) {
        $error = Error.new: absolute => $error;
        given self.bless: :$value, :$error {
            $error!Error::bind-value: .value;
            $_
        }
    }
}

my $m = Measure.new( value => 10, error => 1 );
say $m.error.percent;   # OUTPUT: «10%»
$m.value = 20;
say $m.error.percent;   # OUTPUT: «5%»

那会如你所愿吗?


(此外,额外的想法与您提出的问题无关:percent 让我觉得 完美 用例 allomorph,这会让代码的用户可以使用格式良好的 Str 或他们可以用来做更多数学运算的数值来访问百分比。因此,类似于

do given ( $!absolute / $!measured-value ).abs { RatStr.new: $_, "{$_ × 100}%"}

我知道这是题外话,但它太有趣了,更不用说了!)