【发布时间】:2021-09-17 22:37:55
【问题描述】:
(Moose/Moo 的答案当然是“角色”。这个问题是关于您想要组合两个模块的一般情况,这两个模块都是同一个父级的子类,假设没有 Moose/Moo。)
让我们举一个稍微做作的例子:模块LWP::UserAgent::Determined 和LWP::RobotUA 都是LWP::UserAgent 的子类,并以不同的方式扩展它。如果我想创建一个结合了两者方法的对象,我应该怎么做?它的核心仍然是一个LWP::UserAgent 对象,并且其他两个模块不会相互冲突,所以应该很容易,对吧?
据我所知,正确的做法是创建一个新包,将其他两个都声明为父包 - use parent qw(LWP::RobotUA LWP::UserAgent::Determined) - 然后从中创建对象。而且,确实,如果你这样做,你会得到一个对象,其中包含来自两者的方法,以及来自基类LWP::UserAgent 的方法,并且几乎一切都如你所愿。 p>
但不完全是。 LWP::UserAgent::Determined 和LWP::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 # 使用睡眠? : 1 允许好吗? : 1 有规则的网站:www.bbc.co.uk:443 ################################################## ########## # LWP::UserAgent::Determined # 时间:1,3,15 重试代码:408、500、502、503、504 ################################################## ########## #我的UA# 使用睡眠? : 1 允许好吗? : 1 有规则的网站:www.bbc.co.uk:443 计时:未设置计时默认值! ...但该方法有效:1,5,10,20,60,240 重试代码:未定义! ################################################## ##########在这里你可以看到两个模块的方法都有效,但是LWP::UserAgent::Determined的timing()或codes_to_determinate()方法与LWP::RobotUA结合时没有设置默认值,而LWP::RobotUA的@987654340 @ 方法 是 使用其默认值 1 创建的。但是,手动设置值可以正常工作,否则组合对象会按预期工作。
所以,总而言之:处理这种情况的正确方法是什么,您想将两个模块合并为一个共同的第三个子类?事实上,这是否正确,但我只是选择了一个不幸的示例,LWP::UserAgent::Determined 在设置默认值方面表现不佳?
【问题讨论】:
-
我还没有阅读任何代码,但我怀疑
new方法都没有调用SUPER或类似的方法。所以一半的代码没有被调用。
标签: perl oop lwp-useragent