我正在使用一些Perl软件包,我们称之为Some::Parser
和Some::Data
。 Some::Parser
对象具有返回类型为Some::Data
的对象的方法。我编写了一个扩展Some::Data
类的类,我们称之为My::Data
。类My::Data
的对象实际上只是类Some::Data
的对象,但使用其他方法可以更轻松地使用它们。
我的问题是我想继续使用Some::Parser
类来完成解析数据的艰苦工作。正如我之前所说,Some::Parser
个对象给了我Some::Data
个对象。一旦我掌握了Some::Data
对象,有没有办法将其重新归类为My::Data
对象?我该怎么做?
我完全愿意改变我的方法,假设有人可以提出一个更好的方法来做我想做的事情,但编写我自己的解析器不是我有兴趣做的事情!
答案 0 :(得分:10)
这闻起来像一点点污垢。可能是重新考虑您的策略的时候了。例如,也许您应该编写My::Parser
来返回My::Data
个对象。
但如果您不想这样做,可以手动使用bless
来更改对象的类:
my $obj = Some::Data->new;
bless $obj, 'My::Data';
请参阅perldoc中的bless。
答案 1 :(得分:7)
处理类似这样的事情的最佳方法可能是Some::Parser
提供一种方法来指定它应该用于数据对象的类。例如,HTML::TreeBuilder提供element_class
方法。如果希望TreeBuilder生成HTML::Element
个节点以外的其他节点,则继承HTML::TreeBuilder
并覆盖element_class
以返回所需的节点类。 (TreeBuilder中的实际代码有点复杂,因为在HTML-Tree 4之前有一种不同的机制可以执行此操作,并且新的维护者不想破坏它。)
我认为你没有写Some::Parser
,但也许它已经有了这个功能。如果没有,也许它的维护者会接受补丁。这应该是一个相当简单的改变。您只需添加data_class
方法(sub data_class { 'Some::Data' }
),然后将Some::Data->new
更改为$self->data_class->new
。然后,您可以将Some::Parser
创建为My::Parser
的子类,然后覆盖data_class
。
答案 2 :(得分:5)
你可以重新bless
。
Perl 5中的继承只不过是搜索@ISA
。
答案 3 :(得分:3)
你可以重新bless返回的对象到你想要的任何东西:
#!/usr/bin/perl
package Some::Data;
use strict; use warnings;
sub new { my $class = shift; bless { @_ } => $class }
sub a { $_[0]->{a} }
package My::Data;
use strict; use warnings;
use base 'Some::Data';
sub a_squared {
my $self = shift;
my $v = $self->a;
return $v * $v;
}
package Some::Parser;
use strict; use warnings;
sub new { my $class = shift; bless { @_ } => $class }
sub parse { return Some::Data->new(a => 3) }
package main;
use strict; use warnings;
my $data = Some::Parser->new->parse;
bless $data => 'My::Data';
printf "%.1f\t%.1f\n", $data->a, $data->a_squared;
或者,您可以使用@ cjm的想法:
#!/usr/bin/perl
package Some::Data;
use strict; use warnings;
sub new { my $class = shift; bless { @_ } => $class }
sub a { $_[0]->{a} }
package My::Data;
use strict; use warnings;
use base 'Some::Data';
sub a_squared {
my $self = shift;
my $v = $self->a;
return $v * $v;
}
package Some::Parser;
use strict; use warnings;
sub new { my $class = shift; bless { @_ } => $class }
sub parse {
my $self = shift;
return $self->data_class->new(a => 3);
}
sub data_class { $_[0]->{data_class} }
package main;
use strict; use warnings;
my $data = Some::Parser->new(data_class => 'My::Data')->parse;
printf "%.1f\t%.1f\n", $data->a, $data->a_squared;
答案 4 :(得分:1)
我会考虑重新祝福冒险。一旦你有了一个对象你无法确定它是否是使用它的构造函数(通常是Foo :: new())创建的,或者有人重新祝福了其他一些对象。
问题是,一些构造者很胖,这意味着他们做的不仅仅是祝福:
sub new {
my $pkg = shift;
my ($required) = @_;
croak "Bad call" unless defined $required;
_do_something_magic ($required);
my $self = { 'foo' => $required };
return bless $self, $pkg;
}
在这种情况下,您重新祝福的对象可能不是您以后在代码中所期望的对象。
可以考虑构建具有“重新祝福”功能的构造函数。但是这样的“对象转换器”将使设计更加复杂。
坚持基本定义:“对象是类的一个实例。永远。”