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%
这适用于...
- 它分离了度量“容器”和错误“元素”的关注点
- $.value 正确地保留在度量中,并在需要时“向上”传递
但是
这并不反映许多错误操作将需要测量值这一事实。那么(如何)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.value
是 rw
这样我就可以展示 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}%"}
我知道这是题外话,但它太有趣了,更不用说了!)
我非常喜欢 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%
这适用于...
- 它分离了度量“容器”和错误“元素”的关注点
- $.value 正确地保留在度量中,并在需要时“向上”传递
但是
这并不反映许多错误操作将需要测量值这一事实。那么(如何)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.value
是 rw
这样我就可以展示 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}%"}
我知道这是题外话,但它太有趣了,更不用说了!)