如何在 Moose 中使用单个构建器构建多个属性?
使用 Moose,是否可以创建一个同时构建多个属性的构建器?
我有一个项目,其中对象有多个字段“集” - 如果请求该集中的任何成员,我想继续填充它们。我的假设是,如果我需要姓名,我还需要生日,并且由于它们位于同一个表中,因此在一个查询中获取两者会更快。
我不确定我的问题是否足够清楚,但希望一些示例代码能让它清楚。
我拥有的是:
Package WidgetPerson;
use Moose;
has id => (is => 'ro', isa => 'Int' );
has name => (is => 'ro', lazy => 1, builder => '_build_name');
has birthdate => (is => 'ro', lazy => 1, builder => '_build_birthdate');
has address => (is => 'ro', lazy => 1, builder => '_build_address');
sub _build_name {
my $self = shift;
my ($name) = $dbh->selectrow_array("SELECT name FROM people WHERE id = ?", {}, $self->id);
return $name;
}
sub _build_birthdate {
my $self = shift;
my ($date) = $dbh->selectrow_array("SELECT birthdate FROM people WHERE id = ?", {}, $self->id);
return $date;
}
sub _build_address {
my $self = shift;
my ($date) = $dbh->selectrow_array("SELECT address FROM addresses WHERE person_id = ?", {}, $self->id);
return $date;
}
但我想要的是:
has name => (is => 'ro', isa => 'Str', lazy => 1, builder => '_build_stuff');
has birthdate => (is => 'ro', isa => 'Date', lazy => 1, builder => '_build_stuff');
has address => (is => 'ro', isa => 'Address', lazy => 1, builder => '_build_address');
sub _build_stuff {
my $self = shift;
my ($name, $date) = $dbh->selectrow_array("SELECT name, birthdate FROM people WHERE id = ?", {}, $self->id);
$self->name($name);
$self->birthdate($date);
}
sub _build_address {
#same as before
}
Using Moose, is it possible to create a builder that builds multiple attributes at once?
I have a project in which the object has several 'sets' of fields - if any member of the set is requested, I want to go ahead and populate them all. My assumption is that if I need the name, I'll also need the birthdate, and since they're in the same table, it's faster to get both in one query.
I'm not sure if my question is clear enough, but hopefully some sample code will make it clear.
What I have:
Package WidgetPerson;
use Moose;
has id => (is => 'ro', isa => 'Int' );
has name => (is => 'ro', lazy => 1, builder => '_build_name');
has birthdate => (is => 'ro', lazy => 1, builder => '_build_birthdate');
has address => (is => 'ro', lazy => 1, builder => '_build_address');
sub _build_name {
my $self = shift;
my ($name) = $dbh->selectrow_array("SELECT name FROM people WHERE id = ?", {}, $self->id);
return $name;
}
sub _build_birthdate {
my $self = shift;
my ($date) = $dbh->selectrow_array("SELECT birthdate FROM people WHERE id = ?", {}, $self->id);
return $date;
}
sub _build_address {
my $self = shift;
my ($date) = $dbh->selectrow_array("SELECT address FROM addresses WHERE person_id = ?", {}, $self->id);
return $date;
}
But what I want is:
has name => (is => 'ro', isa => 'Str', lazy => 1, builder => '_build_stuff');
has birthdate => (is => 'ro', isa => 'Date', lazy => 1, builder => '_build_stuff');
has address => (is => 'ro', isa => 'Address', lazy => 1, builder => '_build_address');
sub _build_stuff {
my $self = shift;
my ($name, $date) = $dbh->selectrow_array("SELECT name, birthdate FROM people WHERE id = ?", {}, $self->id);
$self->name($name);
$self->birthdate($date);
}
sub _build_address {
#same as before
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
在这种情况下,当我不想像 Ether 的答案那样拥有一个单独的对象时,我所做的就是为中间状态设置一个延迟构建的属性。因此,例如:
重复与
birthdate
相同的模式来获取姓名等。读取任何单独的属性将尝试从
raw_row
获取数据,其惰性构建器只会运行SQL 一次。由于您的属性都是只读的,因此您不必担心其中一个属性发生更改时更新任何对象状态。这种模式对于 XML 文档之类的东西也很有用——您保存的中间状态可以是 DOM,其中各个属性是从 XPath 表达式或您拥有的东西延迟构建的。
What I do in this case, when I don't want to have a separate object as in Ether's answer, is have a lazily built attribute for the intermediate state. So, for example:
Repeat the same pattern as
birthdate
for name, etc.Reading any of the individual attributes will try to get data from
raw_row
, whose lazy builder will only run the SQL once. Since your attributes are all readonly, you don't have to worry about updating any object state if one of them changes.This pattern is useful for things like XML documents, too -- the intermediate state you save can be e.g. a DOM, with individual attributes being lazily built from XPath expressions or what-have-you.
不可以,属性生成器一次只能返回一个值。您可以通过让每个构建器在返回之前设置另一个属性的值来构建这两个属性,但这很快就会变得丑陋......
但是,如果您通常有两条数据以某种方式组合在一起(例如,来自与您的情况相同的数据库查询),您可以将这些值作为对象一起存储在一个属性中:
No, an attribute builder can only return one value at a time. You could build both by having each builder set the value of the other attribute before returning, but that gets ugly pretty quickly...
However, if you generally have two pieces of data that go together in some way (e.g. coming from the same DB query as in your case), you can store these values together in one attribute as an object: