我想请教您关于属性访问者的建议'命名。
我开始开发一个应该具有相当分层的类层次的项目,例如,SomeFramework
类,一堆像SomeFramework::Logger
这样的类,让我们说,类与SomeFramework::SomeSubsystem::SomeComponent::SomeAPI
类相似。
我的目标是在所有这些类之间设计最有效的通信。我将解释我现在是如何做到的,所以也许你想就如何做得更好分享一些意见。
当我初始化SomeFramework
类时,我有一个从我的应用程序中使用的对象引用。
my $someframework = SomeFramework->new(parameter => 'value');
SomeFramework
类有一些属性,例如logger
,configuration
等,以下是其定义的一些示例:
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"的引用。对象或一些其他值(例如,哈希),它不可能调用该方法。 :(
呃......抱歉这么长时间的咆哮!我希望,你已经设法读到这里。 :)
我很高兴知道你做了什么,你建议做什么。请随意分享您对此主题的任何想法,我们将非常感谢您的任何新想法!
坦率地说,我并不觉得它太可怕了。至于我,如果可以从某个类访问同一个框架内的其他类 ,那就非常好了。为什么不?例如,让我们想象一下,我们为job-queue runner(让我们称之为至于更大的问题,让我看看我是否理解。有苹果和香蕉。冰箱内有两个。但是你希望苹果知道冰箱,而蠕虫应该知道苹果,所以它可以从蠕虫到苹果到冰箱,并在它想睡觉时关掉
$fridge->light
。那是对的吗?听起来像是一个破坏各种设计模式的可怕想法
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!");
}
因此,我们的对象知道如何调用已初始化该对象的框架对象的方法,而且它可以调用框架对象的某些方法,甚至可以调用其他对象的某些方法进行初始化和存储由框架的对象。
如果真的很糟糕,你会非常友好地帮助我理解为什么吗?谢谢!