gpt4 book ai didi

perl - 在我的许多基于 Moose 的子类中重写属性的最有效方法是什么?

转载 作者:行者123 更新时间:2023-12-03 07:49:35 26 4
gpt4 key购买 nike

我正在使用HTML::FormHandler 。要使用它,应该从它派生子类,然后您可以覆盖一些属性,例如 field_name_spaceattribute_name_space

但是,我现在有很多表单都扩展了 HTML::FormHandler 或其基于 DBIC 的变体 HTML::FormHandler::Model::DBIC因此这些被覆盖的属性会重复很多次。

我尝试将它们放入角色中,但收到错误,指出角色不支持 +attr 表示法。很公平。

消除这种重复的最佳方法是什么?我想也许是子类化,但是我必须为 HTML::FormHandlerHTML::FormHandler::Model::DBIC 做两次,而且我相信一般的想法是通常使用角色可以更好地实现子类化。

更新:我认为举个例子是个好主意。这就是我目前正在做的事情 - 它涉及代码重复。正如您所看到的,一种表单使用不同的父类,因此我无法创建一个父类来放置属性覆盖。我必须创建两个 - 这也增加了冗余。

package MyApp::Form::Foo;

# this form does not interface with DBIC
extends 'HTML::Formhandler';

has '+html_prefix' => (default => 1);
has '+field_traits' => (default => sub { ['MyApp::Form::Trait::Field'] });
has '+field_name_space' => (default => 'MyApp::Form::Field');
has '+widget_name_space' => (default => sub { ['MyApp::Form::Widget'] });
has '+widget_wrapper' => (default => 'None');

...

package MyApp::Form::Bar;

# this form uses a DBIC object
extends 'HTML::Formhandler::Model::DBIC';

has '+html_prefix' => (default => 1);
has '+field_traits' => (default => sub { ['MyApp::Form::Trait::Field'] });
has '+field_name_space' => (default => 'MyApp::Form::Field');
has '+widget_name_space' => (default => sub { ['MyApp::Form::Widget'] });
has '+widget_wrapper' => (default => 'None');

...

package MyApp::Form::Baz;

# this form also uses a DBIC object
extends 'HTML::Formhandler::Model::DBIC';

has '+html_prefix' => (default => 1);
has '+field_traits' => (default => sub { ['MyApp::Form::Trait::Field'] });
has '+field_name_space' => (default => 'MyApp::Form::Field');
has '+widget_name_space' => (default => sub { ['MyApp::Form::Widget'] });
has '+widget_wrapper' => (default => 'None');

...

最佳答案

首先,角色被组成一个类,它们与子类化无关。子类是一个完整的类,它扩展了一个父类(或多个父类,但根据我的经验,如果可以的话,应该避免多重继承)。角色是一种行为,或者是可以应用于类的部分接口(interface)。然后角色直接修改类。一般情况下没有创建新类。

所以继承和角色组合实际上是两个不同的东西,也是两种不同的设计。因此,你不能简单地用一种交换另一种。两者都有不同的设计含义。

我使用 HTML::FormHandler 的策略是为我需要的每个表单创建一个真正的子类,并将我想要重用的表单的不同行为放入角色中。

我认为这个问题(如何以干净、理智的方式实现您需要的扩展)在不知道您的实际设计目标的情况下无法真正得到回答。

更新:我明白你的意思,这是一个棘手的情况。 HTML::FormHandler 主要针对通过继承进行扩展。所以我认为最好的策略确实是有两个子类,一个用于 HTML::FormHandler ,一个用于 HTML::FormHandler::Model::DBIC 。乍一看似乎很乏味,但从长远来看,您可能希望对它们进行不同的设置。为了避免重复实际配置(默认值),我会尝试以下操作(此示例是普通 HFH,没有 DBIC):

package MyApp::Form;
use Moose;
use namespace::autoclean;

extends 'HTML::FormHandler';
with 'MyApp::Form::DefaultSettings';

# only using two fields as example
for my $field (qw( html_prefix field_traits )) {
has "+$field", default => sub {
my $self = shift;
my $init = "_get_default_$field";
my $method = $self->can($init)
or die sprintf q{Class %s does not implement %s method}, ref($self), $init;
return $self->$method;
};
}

1;

请注意,如果某个属性需要另一个属性的值进行计算,则需要将其设置为惰性属性。上面的基类将寻找钩子(Hook)来查找初始化值。您必须在两个类中执行此操作,但您可以将默认子例程生成放入从库导入的函数中。由于上面不再需要直接操作属性来更改默认值,因此您可以将这些内容放入我上面称为 MyApp::Form::DefaultSettings 的角色中:

package MyApp::Form::DefaultSettings;
use Moose::Role;
use namespace::autoclean;

sub _build_html_prefix { 1 }
sub _build_field_traits { ['MyApp::Form::Trait::Field'] }

1;

此方法将允许您的角色影响默认值的构造。例如,您可以拥有一个基于上述角色的角色,该角色使用 around 修改值。

还有一种非常简单,但在我看来有点丑陋的方式:您可以让一个角色提供一个 BUILD 方法来更改值。乍一看,这似乎非常简单且简单,但它是以简单性为代价换取了可扩展性/灵活性。它工作起来很简单,但也只适用于非常简单的情况。由于 Web 应用程序中的表单数量通常相当高,并且需求可能非常多样化,因此我建议采用更灵活的解决方案。

关于perl - 在我的许多基于 Moose 的子类中重写属性的最有效方法是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3396526/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com