使用自动生成的公共属性方法与创建访问私有属性的方法

uzl*_*xxx 6 oop attributes class raku

假设我有一个具有多个属性的类,但我只需要其中的一些用于对象构造;其余属性的值取决于这些公共属性。但是,我仍然想使用以属性命名的方法访问其余属性的值。在我的脑海里,有两个选择:

第一个选项:

  • 重载new方法。或者保持new方法BUILD不变,而是使用子方法将传递的参数设置为正确的属性,并使用此参数的值设置剩余的属性。
class Foo {
    has Int $.a;
    has Int $.b;
    has Int $.c;

    submethod BUILD(:$!a) {
        $!b = $!a ** 2;
        $!c = $!a ** 3;
    }
}
Run Code Online (Sandbox Code Playgroud)
say Foo.new(:2a, :1b);   #=> Foo.new(a => 2, b => 4, c => 8)
say Foo.new(:2a, :1b).b; #=> 8
Run Code Online (Sandbox Code Playgroud)

第二种选择:

$.仅声明对象构建所需的那些属性,并在对象构建后使用子方法修改其余属性(用 声明$!TWEAK。但是,现在我需要为这些属性创建访问器方法。

class Bar {
    has Int $.a;
    has Int $!b;
    has Int $!c;

    submethod TWEAK {
        $!b = $!a ** 2;
        $!c = $!a ** 3;
    }

    method b { $!b }
    method c { $!c }
}
Run Code Online (Sandbox Code Playgroud)
say Bar.new(:2a, :1b);   #=> Bar.new(a => 2)
say Bar.new(:2a, :1b).b; #=> 8
Run Code Online (Sandbox Code Playgroud)

问题

什么是最好的选择吗?还有其他选择吗?每个选项的优点/缺点是什么?

Sci*_*mon 7

就我个人而言,我会很简单:

class Foo { 
    has Int $.a; 
    has Int $!b = $!a ** 2; 
    has Int $!c = $!a ** 3;
    method b { $!b }
    method c { $!c }
}
say Foo.new(:2a, :1b); #=>  Foo.new(a => 2)
say Foo.new(:2a, :1b).b; #=> 4
Run Code Online (Sandbox Code Playgroud)

只需使用属性的默认构造函数和默认值,并添加几个基本的读取方法。默认构造函数仅更新公共属性,因此如果您尝试覆盖bc忽略此属性。

如果您愿意,可以BUILD在有人尝试设置错误时添加子方法。

在这个案例(可能是最终用例)的评论中提出了一个很好的观点:

class Foo { 
    has Int $.a; 
    method b() is pure { $!a ** 2 }
    method c() is pure { $!a ** 3 }
}
say Foo.new(:2a, :1b); #=>  Foo.new(a => 2)
say Foo.new(:2a, :1b).b; #=> 4
Run Code Online (Sandbox Code Playgroud)

根据计算的复杂性,您可能也想使用is cachedtrait。