# ./lib/Foo/Classic.pm # -------------------- package Foo::Classic; use warnings; use strict; use feature qw{ say }; use experimental qw( signatures ); use parent 'Foo::Common'; sub style($self) { 'classic' } sub m2($self) { say 'classic 2' } __PACKAGE__ # ./lib/Foo/Constants.pm # ---------------------- package Foo::Constants; use warnings; use strict; use Exporter qw{ import }; my %const; BEGIN { %const = ( ABC => 'abc', XYZ => 'xyz', ); } use constant \%const; our @EXPORT_OK = keys %const; __PACKAGE__ # ./lib/Foo/Modern.pm # ------------------- package Foo::Modern; use warnings; use strict; use feature qw{ say }; use experimental qw( signatures ); use parent 'Foo::Common'; sub style($self) { 'modern' } sub m2($self) { say 'modern 2' } __PACKAGE__ # ./lib/Foo/Builder.pm # -------------------- package Foo::Builder; use warnings; use strict; use experimental qw( signatures ); use Foo::Classic; use Foo::Modern; my %CLASS = (classic => 'Foo::Classic', modern => 'Foo::Modern'); sub new($class) { return bless {}, $class } sub build($self, $style, @args) { my $class = $CLASS{$style}; die "Unknown style $style" unless $class; return $class->new(@args) } __PACKAGE__ # ./lib/Foo/Common.pm # ------------------- package Foo::Common; use warnings; use strict; use feature qw{ say }; use experimental qw( signatures ); sub new($class) { bless {}, $class } sub m1($self) { say $self->style, ' 1' } sub style($self) { die 'Not implemented' } __PACKAGE__ # ./script.pl # ----------- #!/usr/bin/perl use warnings; use strict; use feature qw{ say }; use lib 'lib'; use Foo::Builder; use Foo::Constants qw( ABC XYZ ); my $builder = 'Foo::Builder'->new; my $m = $builder->build('modern'); $m->m1; $m->m2; my $c = $builder->build('classic'); $c->m1; $c->m2; say ABC;