# Build and require the subclass for this type: my $class = __PACKAGE__ . "::" . $opts{type}; eval "require $class"; if ($@) { Carp::carp("Part type '$opts{type}' unknown"); return undef; } # Build the Part object template: my $self = { # name provided directly, or implicitly by type. name => $opts{name} // $opts{type}, }; # Bless into the determined subclass for this type: bless $self, $class; #### use strict; use warnings; require Carp; use lib 'lib'; require Widget; # Create a new widget. my $w = Widget->new or Carp::confess("new widget failed"); # Add a part of type 'Cog' to this widget, named 'cog-62' my $part = $w->addPart(type=>'Cog', name=>'cog-62') or Carp::confess("addPart failed"); # Show some info about the part just added: printf( "part name is: %s, of class: %s\n", $part->name(), ref($part) ); #### package Widget; use strict; use warnings; require Carp; require Widget::Part; sub new { my $class = shift; $class = ref($class) || $class; my $self = { parts => { }, }; bless $self, $class; return $self; } sub addPart { my $self = shift; my %opts = (@_); # Create the new part: my $part; unless ( $part = Widget::Part->new(%opts) ) { Carp::carp("unable to add Widget part"); return undef; } $self->{parts}{$opts{type}} = $part; return $part; # use as bool or ref to part object. } 1; #### package Widget::Part; use strict; use warnings; require Carp; sub new { shift; # throw away this class. We won't use it. my %opts = (@_); # Must have a part 'type' for success. unless (defined $opts{type}) { Carp::carp("no part type provided"); return undef; } # Build and require the subclass for this type: my $class = __PACKAGE__ . "::" . $opts{type}; eval "require $class"; if ($@) { Carp::carp("Part type '$opts{type}' unknown"); return undef; } # Build the Part object template: my $self = { # name provided directly, or implicitly by type. name => $opts{name} // $opts{type}, }; # Bless into the determined subclass for this type: bless $self, $class; # Call subclass initilization code: $self->init(); return $self; } # Basic example accessor: return this part's name. sub name { my $self = shift; return $self->{name}; } 1; #### package Widget::Part::Cog; use strict; use warnings; use parent 'Widget::Part'; sub init { my $self = shift; # Additional 'Cog' attributes would be set up here. # Omitted for example brevity. } 1;