I'm working with a few Perl packages, we'll call them Some::Parser and Some::Data. A Some::Parser object has methods to return objects of type Some::Data. I have written a class that extends the Some::Data class, let's call it My::Data. Objects of class My::Data are really just objects of class Some::Data, but with additional methods that make it easier to work with.
My problem is that I want to continue to use the Some::Parser class to do the hard work of parsing the data. As I said earlier, Some::Parser objects give me Some::Data objects. Once I have a Some::Data object in hand, is there any way to reclassify it as a My::Data object? How would I do this?
I'm totally willing to change my approach, assuming someone can suggest a better way of doing what I want to do, but writi开发者_运维问答ng my own parser is not something I'm interested in doing!
This smells like a bit of a kludge. It might be time to rethink your strategy. For example, maybe you should write My::Parser which returns My::Data objects.
But if you don't want to do that, you can manually use bless to change an object's class:
my $obj = Some::Data->new;
bless $obj, 'My::Data';
See bless in perldoc.
Probably the best way to handle something like this is for Some::Parser to provide a way to specify the class it should be using for data objects. For example, HTML::TreeBuilder provides the element_class method. If you want TreeBuilder to produce something other than HTML::Element nodes, you subclass HTML::TreeBuilder and override element_class to return your desired node class. (The actual code in TreeBuilder is a bit more complex, because there was a different mechanism for doing this prior to HTML-Tree 4, and the new maintainer didn't want to break that.)
I take it that you didn't write Some::Parser, but perhaps it has this capability already. If not, maybe its maintainer will accept a patch. It should be a fairly simple change. You'd just add a data_class method (sub data_class { 'Some::Data' }), and then change Some::Data->new to $self->data_class->new. Then you can subclass Some::Parser to create My::Parser, and just override data_class.
You can rebless anything.
Inheritance in Perl 5 is nothing more than searching @ISA.
You can re-bless the returned object to whatever your heart desires:
#!/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;
Alternatively, you can use @cjm's idea:
#!/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;
I'd consider re-blessing venturesome. Once you have an object you can't really tell if it was created using its constructor ( usually Foo::new() ), or someone re-blessed some other object.
The problem is, some constructors are fat, this means they do a whole lotta more than just blessing something:
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;
}
In this case your re-blessed object might not be the one you'll expect later in code.
One may consider constructors with "re-blessing" functionality build in. But such "object converters" will make the design even more complicated.
Stick to the basic definition: "An object is an instance of the class. Forever.".
加载中,请稍侯......
精彩评论