perl - 在作为另一个对象访问器的对象列表中搜索

perl - searching in list of objects which are an accessor of another object

我是 Perl-OO 初学者,我遇到了设计挑战。我希望你能给我一些提示,以找到一个优雅的解决方案。我在这里使用鼠标对象系统。

举一个最小的例子,假设我有一个用户对象。一个用户有一个名字。

package User;
use Mouse;    

has "name" => (
   is        => "rw",
   isa       => "Str|Undef",
);  

然后我有一个用户缓存对象,它获取所有用户的列表(来自 LDAP 服务器)。你可以说这是用户缓存和用户之间的 "has-a" 关系。

package UserCache;
use Mouse;    

has "users" => (
   is        => 'rw',
   isa       => 'ArrayRef|Undef',
   default   => sub { [] },
);  

我将这个用户列表作为用户对象数组存储在用户缓存的访问器中。

 my $cache = UserCache->new();

 foreach my $entry ( $ldap->searchGetEntries() ) { 
      my $user = User->new();
      $user->name($entry->get_value('userdn'));
      push @{ $cache->users }, $user;
 }

现在这就是我的问题所在。如果我想找到具有特定属性的用户对象(例如,名为 John 的用户),我必须遍历整个用户对象数组并查询每个对象因为它的名字。当给出一个名称列表时,这将是一个非常低效的过程。

foreach my $user ( @{ $cache->users } ) {
      if ( $user->name eq 'John' ) {
           #do something with John
      }...
} 

有没有一种方法可以将对象列表存储在其他对象中,以便我可以高效地搜索?比如 $cache->get_users->get_name('John') 和 returns 我需要的对象?

。至少不是普遍的。您当然可以为常见的事物建立索引。或者您可以在完成搜索后缓存搜索。

查找最好以散列的形式实现。这些可以附加到 UserCache 对象。类似于:

my @users = $cache->find( name => 'John' );

这将在内部映射到带有搜索字段的哈希引用。

package UserCache;
#...

has _search_index => (
    is  => 'ro',
    isa => 'HashRef',
    default => sub { {} },
);

哈希引用看起来像这样:

{
    name => {
        John => [
            User->new( name => 'John', last_name => 'Smith' ),
            User->new( name => 'John', last_name => 'Wayne' ),
            User->new( name => 'John', last_name => 'Bon Jovi' ),
        ],
        James => [ ... ],
    },
    id => {
        # ...
    },
),

但同样,您必须构建这些。所以你需要做一次查找。但我认为查找应该在 UserCache 内部完成并存储在那里。

sub find {
    my ($self, $key, $value) = @_;

    # get operation
    return @{ $self->_search_index->{$key}->{$value} } 
        if exists $self->_search_index->{$key}->{$value};

    # set operation
    foreach my $user ( @{ $self->users } ) {
        push @{ $self->_search_index->{$key}->{$value} }, $user
            if $user->$key eq $value
    }
    return @{ $self->_search_index->{$key}->{$value} } 
}

这是一个非常幼稚的实现,它不支持多次查找,但这是一个开始。

请注意,如果您有很多用户和很多索引,数据结构可能会变大。

为了方便起见,Moose's built-in traits might be helpful. If you want a stronger cache behavior, look at CHI

您实际上不必自己编写 UserCache class。相反,使用 CHI 来缓存您要缓存的用户,该用户要缓存在您要用于查找的键下。如果需要,您可以包装缓存 class 以从特定的缓存实现中抽象出来。

另外,你有这个:

push @{ $cache->users }, $user;

你在哪里泄露了实现细节。相反,您的 UserCache 对象需要类似 save_user 方法的东西,因此它使用的代码不依赖于实现细节。

$cache->save_user( $user );

对于 Moose 对象,您得到 Moose::Meta::Attribute::Native::Trait::Array; for Mouse, you get MouseX::NativeTraits::ArrayRef