#!/usr/bin/perl use strict; use warnings; use Boss1; use Data::Dumper; Boss1->debug(1); my $boss = Boss1->new(); $boss->fullname->title("Don"); $boss->fullname->surname("Pichon Alvarez"); $boss->fullname->christian("Federico Jesus"); $boss->fullname->nickname("Fred"); $boss->salary(40000); $boss->age(47); $boss->peers("Frank", "Felipe", "Faust"); printf "%s is age %d.\n", $boss->fullname->as_string, $boss->age; printf "His peers are: %s\n", join(", ", $boss->peers); print "here is the boss\n"; print Dumper($boss); #### package Boss1; use Employee4; @ISA = qw(Employee4); 1; #### package Employee4; ## ## An example of inheritance with both some further methods defined for the derived class ## and overridden methods demonstrating polymorphism. ## See testemp3.pl . use Person5; ## load this class @ISA = ("Person5"); ## inherit the class methods as needed. use Carp; my $Debugging = 0; ## global in Employee3 ... ## need to initialise the new fields provided by this class sub new { my $class = shift; my $self = $class->SUPER::new(); $self->{SALARY} = undef; $self->{ID} = undef; $self->{START_DATE}; return $self; } ## Unique Employee methods sub salary { my $self = shift; if (@_) { $self->{SALARY} = shift } return $self->{SALARY}; } sub id_number { my $self = shift; if (@_) { $self->{ID} = shift } return $self->{ID}; } sub start_date { my $self = shift; if (@_) { $self->{START_DATE} = shift } return $self->{START_DATE}; } ## Overridden methods - polymorphism ## This completely overrides Person5->peers. sub peers { my $self = shift; if (@_) { @{$self->{PEERS}} = @_; } return map { "PEON=\U$_" } @{ $self->{PEERS} }; } ## subclass/superclass sub debug { my $self = shift; confess "usage: thing->debug(level)" unless @_ = 1; my $level = shift; if (ref($self)) { $self->{_DEBUG} = $level; } else { $Debugging = $level; } $self->SUPER::debug($Debugging); } 1; #### package Person5; ## ## This package is created while following the Perl OO tutorial perlootut. ## ## This fifth class demonstrates inheritance - see the derived classes Employeen, n=1,... ## ## In Person1, global data was accessed directly within the class and object methods. ## This behaviour prevents both scalability and inheritance. ## In Person2 access to global data is acheived by defining a class member which is a reference to the ## global data. This member is then part of the class definition and can be carried forward in ## inheritance. ## Person3 added a bimodal (class or object) debugging technique and the END routine, executed ## implicitly when a program quits. ## Person4 added improved pod and demonstrated class aggregation using the Fullname class. ## Aggregation is where a class is part of another class. It is not inheritance. ## ## Q. If this class is inherited, then what does Census apply to? use strict; ## Examples of class data : $Census and $Debugging ## my $Census = 0; ## a file scoped lexical class datum ## use Carp; my $Debugging = 0;## oh look another file-scoped lexical variable, deeply bound so it won't go out of scope until it isn't needed anymore use Fullname; ## making this class aware of the Fullname class ## The constructor ## - built as a class method ## - designed to be inheritable ## - there is no restriction on the constructor name, could have called this method Person ## - this constructor works on class data and does it well. sub new { my $class= shift; ## this exploits the class method nature of invocation. my $self = {}; ## a hash reference $self->{FULLNAME} = Fullname->new(); ## fullname field support introduced. The FULLNAME field is a hash ref to a Fullname object. ## This enables us to use this syntax : $him->fullname->nickname; $self->{NAME} = undef; ## define some elements in the hash $self->{AGE} = undef; $self->{PEERS} = []; $self->{"_CENSUS"} = \$Census; ## Take a reference to the global variable. Preceding underscore indicative of magic. ## This is 'private' data and now the object being created contains a reference to ## global data i.e. the global data is not accessed directly. bless($self,$class); ## tell the reference it is an object in the $class namespace ## this class becomes inheritable because we use the $class passed in, and not the current (Person1) class/namespace ++ ${ $self->{"_CENSUS"} }; return $self; } ## a new "bimodal" method (class or object) which sets the global variable $Debugging either by direct access for the class method ## or sets up a reference to the debug level within the object. ## This maintains scalability and keeps the class inheritable. sub debug { my $self = shift; confess "usage: thing->debug(level)" unless @_ = 1; my $level = shift; if (ref $self) { $self->{"_DEBUG"} = $level; ## just set the debug level for the object; } else { $Debugging = $level; ## do it for the whole class } } ## These methods access per-object data ## - all will set the item concerned where an argument is given ## - all will return the item value ## - all these methods work directly on the hash value sub fullname { my $self = shift; return $self->{FULLNAME}; ## Returns the hash ref of the fullname object so can use $him->fullname->title etc.. } sub name { ## this method changes to accomodate the new information. my $self = shift; ## move the object off the argument stack ## if (@_) { $self->{NAME} = shift } ##if there is anything left assume the first is the name return $self->{FULLNAME}->nickname(@_) || $self->{FULLNAME}->christian(@_); } sub age { my $self = shift; ## again shift the object off the stack if (@_) { $self->{AGE} = shift } ## if any left assume it is the object's age. return $self->{AGE}; } sub peers { my $self = shift; ## once more shift the object off the argument stack if (@_) { $self->{PEERS} = @_ } ## This is a list/array of peers return $self->{PEERS}; } ## Other methods in the class ## ## Use the previously defined data access methods ## which will be slower but will protect against changes in internal representation ## sub exclaim { my $self = shift; return sprintf "Hi I'm %s, age %d, working with %s", $self->name, $self->age, join(",",$self->peers); } sub happy_birthday { my $self = shift; return $self->age($self->age() +1 ); } ## return either the value of $self->{"_CENSUS"}'s referent or the value of the global data ## when no object has been passed in. sub population { my $self = shift; if ( ref $self ) { ## if a reference has called this, i.e. an object. printf $self->name."\n"; return ${$self->{"_CENSUS"} } ; ## return a reference to the scalar value } else { return $Census; } } ## when a Person object dies need to delete them from the population ## use the implicitly called DESTROY method ## only called when an object has to be destroyed so no need to check the status of $self. sub DESTROY { my $self = shift; if ($Debugging || $self->{"_DEBUG"}) { carp 'Destroying $self ' . $self->name() } -- ${ $self->{"_CENSUS"} }; } ## ## The END function is the final end of the class, typically called in a LIFO order when the program exits ## which is why we use print because Carp will have already ENDed. sub END { if ($Debugging) { print "All persons are going away now\n"; } } =head1 NAME Person - class to implement people =head1 SYNOPSIS use Person; ################# # class methods # ################# $ob = Person->new; $count = Person->population; ####################### object data methods # ####################### ### get versions ### $who = $ob->name; $years = $ob->age; @pals = $ob->peers; ### set versions ### $ob->name("Jason"); $ob->age(23); $ob->peers( "Norbert", "Rhys", "Phineas" ); ######################## # other object methods # ######################## $phrase = $ob->exclaim; $ob->happy_birthday; =head1 DESCRIPTION The Person class implements dah dee dah dee dah.... =cut 1; #### Don Federico Jesus Pichon Alvarez is age 47. His peers are: PEON=FRANK, PEON=FELIPE, PEON=FAUST here is the boss $VAR1 = bless( { 'ID' => undef, 'PEERS' => [ 'Frank', 'Felipe', 'Faust' ], 'NAME' => undef, 'AGE' => 47, 'SALARY' => 40000, '_CENSUS' => \1, 'FULLNAME' => bless( { 'SURNAME' => 'Pichon Alvarez', 'TITLE' => 'Don', 'CHRISTIAN' => 'Federico Jesus', 'NICK' => 'Fred' }, 'Fullname' ) }, 'Boss1' ); Destroying $self Fred at ./testboss1.pl line 0 All persons are going away now