A.7. Answers for Chapter 8Section 8.11.1)

![]() | ![]() |
A.7. Answers for Chapter 8
Section 8.11.1)
Here's one way to do it. First define the
Animal class, with a single method:use strict;
{ package Animal;
sub speak {
my $class = shift;
print "a $class goes ", $class->sound, "!\n";
}
}
Now define each subclass with a specific sound:{ package Cow;
our @ISA = qw(Animal);
sub sound { "moooo" }
}
{ package Horse;
our @ISA = qw(Animal);
sub sound { "neigh" }
}
{ package Sheep;
our @ISA = qw(Animal);
sub sound { "baaaah" }
}
The Mouse package is slightly different because of
the extra quietness:{ package Mouse;
our @ISA = qw(Animal);
sub sound { "squeak" }
sub speak {
my $class = shift;
$class->SUPER::speak;
print "[but you can barely hear it!]\n";
}
}
Now, enter the interactive part of the program:my @barnyard = ( );
{
print "enter an animal (empty to finish): ";
chomp(my $animal = <STDIN>);
$animal = ucfirst lc $animal; # canonicalize
last unless $animal =~ /^(Cow|Horse|Sheep|Mouse)$/;
push @barnyard, $animal;
redo;
}
foreach my $beast (@barnyard) {
$beast->speak;
}
This code uses a simple check, via a pattern match, to ensure that
the user doesn't enter Alpaca or
another unavailable animal, because doing so will crash the program.
In Chapter 9, you learned about the
isa method, which lets you check more simply
whether something is an available animal, even allowing for the
possibility that it is an animal that was added to the program after
the check was written.Section 8.11.2)
Here's one way to do it. First, create the base
class of LivingCreature with a single
speak method:use strict;
{ package LivingCreature;
sub speak {
my $class = shift;
if (@_) { # something to say
print "a $class goes '@_'\n";
} else {
print "a $class goes ", $class->sound, "\n";
}
}
}
A person is a living creature, so define the derived class here:{ package Person;
our @ISA = qw(LivingCreature);
sub sound { "hmmmm" }
}
The Animal class comes next, making appropriate
sounds, but unable to talk (except to Dr. Doolittle):{ package Animal;
our @ISA = qw(LivingCreature);
sub sound { die "all Animals should define a sound" }
sub speak {
my $class = shift;
die "animals can't talk!" if @_;
$class->SUPER::speak;
}
}
{ package Cow;
our @ISA = qw(Animal);
sub sound { "moooo" }
}
{ package Horse;
our @ISA = qw(Animal);
sub sound { "neigh" }
}
{ package Sheep;
our @ISA = qw(Animal);
sub sound { "baaaah" }
}
{ package Mouse;
our @ISA = qw(Animal);
sub sound { "squeak" }
sub speak {
my $class = shift;
$class->SUPER::speak;
print "[but you can barely hear it!]\n";
}
}
Finally, have the person speak:Person->speak; # just hmms
Person->speak("Hello, world!");
Notice that the main speak routine has now moved
into the LivingCreature class, which means you
don't need to write it again to use it in
Person. In Animal, though, you
need to check that to ensure an Animal
won't try to speak before calling
SUPER::speak.Although it's not the way the assignment was
written, you can get a similar result if you choose to make
Person a subclass of Animal.
(In that case, LivingCreature would presumably be
needed as a parent class for an eventual Plant
class.) Of course, since an Animal
can't speak, how can a Person?
The answer is that Person::speak would have to
handle its parameters, if any, before or after (or instead of)
calling SUPER::speak.Which would be the better way to implement
this? It all depends upon what classes you'll need
in the future and how you'll use them. If you expect
to add features to Animal that would be needed for
Person, it makes sense for
Person to inherit from Animal.
If the two are nearly completely distinct, and nearly anything that a
Person has in common with an
Animal is common to all
LivingCreature s, it's probably
better to avoid the extra inheritance step. The ability to design a
suitable inheritance structure is a crucial talent for any OOP
programmer.In fact, you may find that after developing the code one way,
you'll want to
"refactor" the code a different
way. This is common with OOP. However, it's very
important to have enough testing in place to ensure that you
don't break things while you're
moving them around.
![]() | ![]() | ![]() |
A.6. Answers for Chapter 7 | ![]() | A.8. Answer for Chapter 9 |

Copyright © 2003 O'Reilly & Associates. All rights reserved.