Perl5 - Moose - 属性访问者'名称

时间:2015-10-23 10:29:52

标签: perl oop moose

我想请教您关于属性访问者的建议'命名。

我开始开发一个应该具有相当分层的类层次的项目,例如,SomeFramework类,一堆像SomeFramework::Logger这样的类,让我们说,类与SomeFramework::SomeSubsystem::SomeComponent::SomeAPI类相似。

我的目标是在所有这些类之间设计最有效的通信。我将解释我现在是如何做到的,所以也许你想就如何做得更好分享一些意见。

当我初始化SomeFramework类时,我有一个从我的应用程序中使用的对象引用。

my $someframework = SomeFramework->new(parameter => 'value');

SomeFramework类有一些属性,例如loggerconfiguration等,以下是其定义的一些示例:

has 'logger' => (
    is          => 'ro',
    isa         => 'SomeFramework::Logger',
    reader      => 'get_logger',
    writer      => '_set_logger',
    builder     => '_build_logger',
    lazy        => 1
);

sub _build_logger {

    my $self = shift;

    SomeFramework::Logger->new(someframework => $self);

}

我将对父对象的引用传递给子对象,因为我需要子进程访问父对象及其方法&存取。所以在SomeFramework::Logger我有这样的属性:

has 'someframework' => (
    is          => 'ro',
    isa         => 'SomeFramework',
    reader      => 'get_someframework',
    writer      => '_set_someframework',
    required    => 1
);

它让我可以访问SomeFramework::Logger类中的任何对象,通常它看起来像这样:

my $configuration =
     $self->
     get_someframework->
     get_configuration->
     get_blah_blah;

为了推断它,让我们看看SomeFramework::SomeSubsystem::SomeComponent::SomeAPI类。这个班级有自己的父母"属性(让我们称之为somecomponent),它应该具有对SomeFramework::SomeSubsystem::SomeComponent对象的引用作为值。 SomeFramework::SomeSubsystem::SomeComponent类具有其自己的父属性(我们可以称之为somesubsystem)的属性,该属性应该包含对SomeFramework::SomeSubsystem对象的引用。最后,此类也具有其自己父级的属性(someframework),因此它包含对SomeFramework对象的引用。

这一切都可以在SomeFramework::SomeSubsystem::SomeComponent::SomeAPI类中包含类似内容:

my $configuration =
    $self->
    get_someframework->
    get_somesubsystem->
    get_somecomponent->
    get_configuration->
    get_blah_blah;

我想知道的第一件事是:这是一个好习惯吗?我希望,是的,但也许你会建议我采取更顺畅的方式吗?

第二个问题有点复杂(对我而言),但我希望你能帮助我。 :)我喜欢D.Conway在他的" Perl最佳实践"中推荐的访问者的规范名称,但我想做类似的事情:

my $configuration = $self->sc->ss->sf->conf->blah_blah;

当然,我可以用这种简洁的方式为所有读者命名:

has 'some_framework' => (
    is          => 'ro',
    isa         => 'SomeFramework',
    reader      => 'sf',
    writer      => '_set_someframework',
    required    => 1
);

但我不喜欢没有"标准的管理理念。访问者名称。 :(

我也可以使用MooseX::Aliases,它适用于类似的东西:

has 'some_framework' => (
    is          => 'ro',
    isa         => 'SomeFramework',
    reader      => 'get_someframework',
    writer      => '_set_someframework',
    required    => 1,
    alias       => 'sf'
);

它看起来很好,但是属性的问题是不需要缩短名称。例如:

has 'api' => (
    is          => 'ro',
    isa         => 'SomeFramework::SomeSubsystem::SomeComponent::API',
    reader      => '_get_api',
    writer      => '_set_api',
    required    => 1,
    alias       => 'api'
);

在这种情况下,Moose会抛出异常:Conflicting init_args: (api, api) at constructor。 :(据我所知,MooseX :: Aliases试图用init_args参数的相同值创建一个属性,所以它失败了。顺便说一下,有时它会发生,但有时它工作正常,我没有&#39 ;发现它什么时候无法正常工作。

也许我应该有类似的东西:

has 'api' => (
    is          => 'ro',
    isa         => 'SomeFramework::SomeSubsystem::SomeComponent::API',
    reader      => '_get_api',
    writer      => '_set_api',
    required    => 1,
    handles     => {
        api => 'return_self' # It's supposed to have some method that only
                             # returns the reference to its own object
    }
);

?但它似乎也不是最好的选择,因为只有当属性包含一个引用时,它才能帮助我,我可以为其定义return_self方法。如果该属性包含对某些" foreign"的引用。对象或一些其他值(例如,哈希),它不可能调用该方法。 :(

呃......抱歉这么长时间的咆哮!我希望,你已经设法读到这里。 :)

我很高兴知道你做了什么,你建议做什么。请随意分享您对此主题的任何想法,我们将非常感谢您的任何新想法!

于2015年10月25日更新

  

至于更大的问题,让我看看我是否理解。有苹果和香蕉。冰箱内有两个。但是你希望苹果知道冰箱,而蠕虫应该知道苹果,所以它可以从蠕虫到苹果到冰箱,并在它想睡觉时关掉$fridge->light。那是对的吗?听起来像是一个破坏各种设计模式的可怕想法

坦率地说,我并不觉得它太可怕了。至于我,如果可以从某个类访问同一个框架内的其他类 ,那就非常好了。为什么不?例如,让我们想象一下,我们为job-queue runner(让我们称之为SomeFramework::JobsQueue::Executor)和一些类作业提供了一些类。做以下事情真的很糟糕:

package SomeFramework::JobsQueue::Executor;

use Moose;
use MooseX::Params::Validate;

has queue {
    isa      => 'SomeFramework::JobsQueue',
    required => 1,
    reader   => 'get_queue',
    writer   => '_set_queue'
}
# This attribute is being set by the framework when the framework
# creates the SomeFramework::JobsQueue::Executor-based object

sub execute {
    my($self, $job, $options) = validated_hash(
        \@_,
        job     => { isa => 'SomeFramework::JobsQueue::Job' },
        options => { isa => 'HashRef' }
    );
    my $queue = $self->get_queue;
    $queue->mark_as_running($job->get_id);
    $job->execute(options => $options);
    $queue->mark_as_completed($job->get_id);
}

?因此,我们的queue-runner对象知道它所属的队列对象" to,所以它可以调用这个队列对象的一些方法。

或者让我们看看更简单的例子:

package SomeFramework::SomeSubsystem;

use Moose;

has 'some_framework' => {
    isa      => 'SomeFramework',
    required => 1,
    reader   => 'get_some_framework',
    writer   => '_set_some_framework'
}

sub some_method {
    my $self = shift;
    $self->get_some_framework->get_logger->log_trace("Hello, world!");
}

因此,我们的对象知道如何调用已初始化该对象的框架对象的方法,而且它可以调用框架对象的某些方法,甚至可以调用其他对象的某些方法进行初始化和存储由框架的对象。

如果真的很糟糕,你会非常友好地帮助我理解为什么吗?谢谢!

0 个答案:

没有答案