Raku OO 可以帮助我避免集成层样板吗

p6s*_*eve 12 oop raku

我非常喜欢 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%
Run Code Online (Sandbox Code Playgroud)

这在...

  • 它将测量“容器”和错误“元素”的关注点分开
  • $.value 正确地保留在度量中,并在需要时“向上”传递

它并不反映许多错误操作将需要测量值的事实。那么(如何)Raku 的酷 OO 模式可以帮助我将“代理”放置到 Error 类中的 $.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!
Run Code Online (Sandbox Code Playgroud)

因此,我正在探索的概念是为 $.value 创建某种闭包/函数,并将其推入构造时的 Error 属性中。

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

cod*_*ons 12

我不能 100% 确定我已经掌握了您想要实现的目标,因此我将首先解释一下我认为您的目标是什么,然后说明我将如何解决该问题。如果我解决了错误的问题,请纠正我。

\n

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

\n

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

\n

基本思想是给出Error一个$!measured-value字段,然后将该字段绑定到关联的Measure\'s $.value。看起来是这样的:

\n
class Measure {...}\nclass Error  {\n    trusts Measure;\n    has Real  $.absolute;\n    has Real  $!measured-value;\n\n    method !bind-value(\\value) { $!measured-value := value };\n\n    method percent {\n        "{ ( $!absolute / $!measured-value ).abs * 100 }%"\n    }\n}\n\nclass Measure {\n    has Real  $.value is rw;\n    has Error $.error;\n\n    method new(:$value, :$error is copy) {\n        $error = Error.new: absolute => $error;\n        given self.bless: :$value, :$error {\n            $error!Error::bind-value: .value;\n            $_\n        }\n    }\n}\n\nmy $m = Measure.new( value => 10, error => 1 );\nsay $m.error.percent;   # OUTPUT: \xc2\xab10%\xc2\xbb\n$m.value = 20;\nsay $m.error.percent;   # OUTPUT: \xc2\xab5%\xc2\xbb\n
Run Code Online (Sandbox Code Playgroud)\n

那会达到你想要的效果吗?

\n
\n

(另外,与您提出的问题无关的额外想法:percent让我觉得这是allomorph的完美用例,这将使代码的用户可以访问百分比,无论是格式良好的还是数字值,他们可以做更多的事情数学与。所以,像Str

\n
do given ( $!absolute / $!measured-value ).abs { RatStr.new: $_, "{$_ \xc3\x97 100}%"}\n
Run Code Online (Sandbox Code Playgroud)\n

我意识到这是一个旁白,但它太有趣了,更不用说!)

\n

  • 为了关闭循环,这现在是在我即将推出的Physics::Error模块中实现的WIP...我对此答案做了三项调整(i)放弃了信任关系并使方法绑定公开以避免与这两个模块的循环依赖不同的文件 (ii) 将对 $!error.bind-value( $!value) 的调用移至方法 TWEAK 以避免稍微费脑子的 ``given self.bless ...``` 构造以及 (iii) 仍然在思考关于同质异形体的优点/缺点(虽然是个好主意) (2认同)