gpt4 book ai didi

perl - 在 Perl 中处理共享公共(public) "ancestor"的模块的多重继承的正确方法是什么?

转载 作者:行者123 更新时间:2023-12-04 11:54:48 26 4
gpt4 key购买 nike

(当然,Moose/Moo 的答案是“角色”。这个问题是关于一般情况,假设没有 Moose/Moo,你想要组合两个模块,它们都是同一个父类的子类。)
让我们举一个稍微做作的例子:模块 LWP::UserAgent::Determined LWP::RobotUA 都是 LWP::UserAgent 的子类并以不同的方式扩展它。如果我想创建一个结合了两者方法的对象,我该怎么办?它的核心仍然是 LWP::UserAgent对象,另外两个模块不会相互冲突,所以应该很容易,对吧?
据我所知,正确的做法是创建一个新包,将其他两个都声明为父包 – use parent qw(LWP::RobotUA LWP::UserAgent::Determined) – 然后从中创建对象。而且,确实,如果你这样做,你会得到一个对象,它包含来自两者的方法,以及来自基类 LWP::UserAgent 的方法。 ,并且几乎一切都如您所愿。
但不完全是。两者 LWP::UserAgent::DeterminedLWP::RobotUA如果没有给出其他值,则在创建对象时设置某些属性的默认值。两者结合时,LWP::RobotUA的默认值被设置,但不是 LWP::UserAgent::Determined的。所以一定是出了什么问题。
下面是一些测试代码:

#!/usr/bin/env perl

use strict;
use warnings;
use 5.016;

use LWP::RobotUA;
use LWP::UserAgent::Determined;

package MyUA;
use parent qw(LWP::RobotUA LWP::UserAgent::Determined);

for my $module (qw(LWP::RobotUA LWP::UserAgent::Determined MyUA)) {
say '# ', $module, ' #';
my $ua = $module->new(
'agent' => 'Test-UA',
'from' => 'example@example.com',
);
my $req = HTTP::Request->new(GET => 'https://www.bbc.co.uk/emp/network_status.txt');
my $response = $ua->request($req);
unless ($module eq 'LWP::UserAgent::Determined') {
say 'Use sleep? : ', $ua->use_sleep() // 'not defined!';
say 'Allowed OK? : ', $ua->rules->allowed('https://www.bbc.co.uk/') // 'not defined!';
say 'Sites with rules: ', (defined $ua->rules()->{loc}) ? join(', ', (sort keys %{$ua->rules()->{loc}})) : 'not defined!';
}
unless ($module eq 'LWP::RobotUA') {
print 'Timings: ';
if (defined $ua->timing()) {
say $ua->timing();
}
else {
print 'Timing defaults not set! ';
$ua->timing('1,5,10,20,60,240');
say '...but the method works: ', $ua->timing();
}
say 'Retry codes: ', (defined $ua->codes_to_determinate()) ? join(', ', (sort keys %{$ua->codes_to_determinate()})) : 'not defined!';
}
say '#'x60;
}
这输出:
# LWP::RobotUA #
使用 sleep ? : 1
允许好吗? : 1
有规则的网站:www.bbc.co.uk:443
############################################### ###########
# LWP::UserAgent::Determined #
时间:1,3,15
重试代码:408、500、502、503、504
############################################### ###########
#我的UA#
使用 sleep ? : 1
允许好吗? : 1
有规则的网站:www.bbc.co.uk:443
计时:未设置计时默认值! ...但该方法有效:1,5,10,20,60,240
重试代码:未定义!
############################################### ###########

在这里您可以看到两个模块的方法都有效,但没有为 LWP::UserAgent::Determined 设置默认值。的 timing()codes_to_determinate()LWP::RobotUA 结合使用时的方法, 而 LWP::RobotUAuse_sleep()方法是使用其默认值 1 创建的.但是,手动设置值可以正常工作,否则组合对象会按预期工作。
所以,总而言之:处理这种情况的正确方法是什么,您想组合两个模块,这些模块是共同的第三个子类?事实上,这是否正确,但我只是选择了一个不幸的例子和 LWP::UserAgent::Determined在如何设置默认值方面表现不佳?

最佳答案

你的新类实际上是这样的:

package MyUA;

use parent qw(LWP::RobotUA LWP::UserAgent::Determined);

1;
让我们像这样测试它:
#!/usr/bin/perl

use strict;
use warnings;
use feature 'say';

use MyUA;

my $ua = MyUA->new(
agent => 'test',
from => 'me@example.com',
);

say ref $ua;
这告诉我们我们有“MyUA”对象。但它到底是什么?我们做了什么?
好吧,对象是使用构造函数方法构建的。这(通常)被称为 new() .在这种情况下,您还没有定义 new()类中的方法。所以 Perl 会在父类(super class)中寻找方法。它通过搜索它在 @INC 中找到的类来实现这一点。并查看每个是否依次包含一个 new()方法。
你的两个父类(super class)都有一个 new()方法。但是 Perl 只需要一个。因此,当它找到一个时,它会停止查找并调用该方法。它调用的第一个是 LWP::RobotUA 中的那个(因为这是传递给 use parent 的列表中的第一个)。所以那个人被调用了。
这意味着您在此处实际获得的是 LWP::RobotUA 类的对象。嗯,主要是。它被祝福到了正确的类中,如果您调用 LWP::UserAgent::Determined 中但不在 LWP::RobotUA 中的任何方法,它仍然可以工作。但是没有调用 LWP::UserAgent::Determined 初始化代码。
这很好地证明了为什么多重继承是个坏主意。除了最微不足道的情况外,在所有情况下都很难做到正确。
我不能在这里给你答案。因为只有您知道您需要两个父类(super class)中的哪一部分。但解决方案将涉及添加您自己的 new()方法到您的类,并可能从其中调用两个父类(super class)构造函数。
更新:好的,我仔细看了看。这可能比我想象的要容易。 LWP::RobotUA::new()拨打 LWP::UserAgent::new()在做各种其他事情的过程中。但是 LWP::UserAgent::Determined::new()拨打 LWP::UserAgent::new()在其处理开始时,然后将其所有其他初始化有用地捆绑在一个名为 _determined_init() 的单独方法中。 .
因此,您的解决方案看起来很简单,只需添加如下构造函数方法:
sub new {
my $class = shift;
my $self = $class->SUPER::new(@_);
$self->_determined_init();

return $self;
}
调用 $class->SUPER::new()电话 LWP::RobotUA::new()因为那是 @INC 的第一个类.反过来,这会调用 LWP::UserAgent::new() - 这样初始化就完成了。然后我们只需拨打 _determined_init()为了初始化另一个父类(super class)。
它似乎适用于我的(非常基本的)测试。但我仍然对多重继承非常怀疑:-)
更新 2:是的。 ikegami is right .我的解决方案只解决了构建对象的问题。我没有考虑实际使用它。

关于perl - 在 Perl 中处理共享公共(public) "ancestor"的模块的多重继承的正确方法是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/68285072/

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