【问题标题】:Can Raku OO help me avoid integration layer boilerplateRaku OO 可以帮助我避免集成层样板吗
【发布时间】:2021-09-23 18:17:29
【问题描述】:

我非常喜欢 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%

这适用于...

  • 它将Measure“容器”和Error“元素”的关注点分开
  • $.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!

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

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

【问题讨论】:

    标签: oop raku


    【解决方案1】:

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

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

    如果是这样,这是一种方法。我不确定它是否比您在上面发布的这个打高尔夫球的示例中的代码简洁得多,但它避免了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}%"}
    

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

    【讨论】:

    • 嗨@codesections - 这正是我正在寻找的......我对绑定感到困惑......但没有明确的想法来提出绑定值私有类方法......以及信任关系......很棒!
    • 结束循环,这现在是在我即将推出的 Physics::Error 模块中实现的 WIP ...我对这个答案进行了三处调整 (i) 删除了信任关系并将方法绑定到 public避免与这两个模块在不同文件中的循环依赖 (ii) 将对 $!error.bind-value( $!value) 的调用移动到方法 TWEAK 以避免稍微弯曲given self.bless ... 构造和 (iii) 仍然在异形体的优点/缺点(虽然是个好主意)
    猜你喜欢
    • 1970-01-01
    • 2023-03-18
    • 2014-06-22
    • 2012-02-01
    • 2018-08-12
    • 2018-09-28
    • 1970-01-01
    • 2016-06-23
    • 1970-01-01
    相关资源
    最近更新 更多