package GenObj;
my %methods = (
name => sub { $_[0]{DATA}{name} },
setname => sub { $_[0]{DATA}{name} = $_[1] },
# ...
);
sub new {
my ($class) = @_;
bless { DATA => {}, METHODS => {%methods} }, $class;
}
AUTOLOAD {
(my $method = $AUTOLOAD) =~ s/.*:://;
$_[0]{METHODS}{$method} ?
goto &{$_[0]{METHODS}{$method}} :
die "unsupported method $method for object";
}
package main;
$foo = GenObj->new;
$foo->setname("Jeff");
print $foo->name;
####
$x = new GenObj; # ref($x) eq 'GenObj::a'
$y = new GenObj -foo; # ref($y) eq 'GenObj::b'
$x->get_foo; # calls $x->GenObj::get_foo
$y->get_foo; # calls $y->GenObj::b::get_foo
####
package GenObj;
# the following methods can be generated
# automatically with one of the Class::
# modules...
# these are the EXPECTED inherited methods
# of GenObj objects
sub set_name { $_[0]{name} = $_[1] }
sub get_name { $_[0]{name} }
sub set_age { $_[0]{age} = $_[1] }
sub get_age { $_[0]{age} }
my $CHILD = 'a';
sub new {
no strict 'refs'; # naughty things transpire
my $class = shift;
my $obj = bless {}, "${class}::$CHILD";
@{"${class}::${CHILD}::ISA"} = ($class);
for (map s/^-//, @_) {
*{"${class}::${CHILD}::get_$_"} =
\&{"${class}::Sub::get_$_"};
*{"${class}::${CHILD}::set_$_"} =
\&{"${class}::Sub::set_$_"};
}
return $obj;
);
package GenObj::Sub;
# these are the specialized methods
# to be inherited on demand
sub set_name { $_[0]{name} = condense($_[1]) }
sub get_name { expand($_[0]{name}) }
sub set_age { $_[0]{age} = age2sec($_[1]) }
sub get_age { sec2age($_[0]{age}) }
# these are some utility functions
# as called above
sub condense;
sub expand;
sub age2sec;
sub sec2age;
1;
####
use GenObj;
my $normal = new GenObj;
my $diffage = new GenObj -age;
my $diffname = new GenObj -name;
my $diffboth = new GenObj -age, -name;
$normal->set_age(10); # GenObj::set_age
$normal->get_name; # GenObj::get_name
$diffage->set_age(10); # GenObj::Sub::set_age
$diffage->get_name; # GenObj::get_name
$diffname->set_age(10); # GenObj::set_age
$diffname->get_name; # GenObj::Sub::get_name
$diffboth->set_age(10); # GenObj::Sub::set_age
$diffboth->get_name; # GenObj::Sub::get_name