如何重新分类Perl对象

时间:2010-10-28 21:42:59

标签: perl oop inheritance

我正在使用一些Perl软件包,我们称之为Some::ParserSome::DataSome::Parser对象具有返回类型为Some::Data的对象的方法。我编写了一个扩展Some::Data类的类,我们称之为My::Data。类My::Data的对象实际上只是类Some::Data的对象,但使用其他方法可以更轻松地使用它们。

我的问题是我想继续使用Some::Parser类来完成解析数据的艰苦工作。正如我之前所说,Some::Parser个对象给了我Some::Data个对象。一旦我掌握了Some::Data对象,有没有办法将其重新归类为My::Data对象?我该怎么做?

我完全愿意改变我的方法,假设有人可以提出一个更好的方法来做我想做的事情,但编写我自己的解析器不是我有兴趣做的事情!

5 个答案:

答案 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;
}

在这种情况下,您重新祝福的对象可能不是您以后在代码中所期望的对象。

可以考虑构建具有“重新祝福”功能的构造函数。但是这样的“对象转换器”将使设计更加复杂。

坚持基本定义:“对象是类的一个实例。永远。”