CGI and Perl

Object-Oriented Techniques

I've already discussed some of the object-oriented functionality in Perl5, but I've intentionally ignored some details until now, in order to present them in a single section. Let's take a look at this functionality now in depth. Motivation After you become familiar with a module and its functionality and use, you may find yourself wishing for this feature or a method which is not implemented within the module. Say, for instance, that you obtain a module that provides you with a new() method to create an X object and perform operations on the X object such as Y() and Z(). Now suppose that you need to also be able to perform the A() operation on the X object. What would you do?

In the Perl4 days, you had two options. The first, and easiest, would have been to write to the author of the library or program, and ask him or her to add a subroutine to perform A() on the internal variable, X, for the next release. The author, assuming he or she had the same e-mail address published in the library or its README file and, more importantly, had the time and the desire to maintain and upgrade the code, would then consider your request and hopefully answer you with an affirmative reply. You would then wait patiently for the next release.

The other option would have been to copy the library or program, and then develop your own (private) additions and enhancements to it so that it would provide the A() subroutine, which you needed. Then, being a good Netizen, you would submit your changes back to the author, in the form of a patch, so that the functionality you added could (when tested and verified) be added to a later release. If the author decided that your new functionality wasn't appropriate for the master release and did not include it, then you were faced with the ongoing, repetitive task of obtaining the latest release and then figuring out how to fold in the new features and bug fixes from it into your own customized version. Clearly, this process can become a bit messy and time consuming as time goes on. Inheritance Nowadays, you can largely eliminate this dilemma by using the object-oriented features that you get with Perl5. If you need the functionality of a module but want to augment or even override its methods, doing so is a relatively simple matter. After you implement these additional features, submitting them to the author is still good Netizenship, but if he or she decides not to implement them in a future release, you're still in good shape. You simply install the next release of the augmented module, and your enhancements still work. You don't need to maintain separate copies, either.

Suppose you're using the Customer module, and everything is going fine. Now, say you want to add a method that would operate on the Customer object to provide a means to search for and return a particular aspect about a customer. You would then write a new module, perhaps called MyCust, and import all the functionality and methods from the Customer module. Then you would need to add only your method, search() to MyCust, to have all the functionality of Customer, including your search() method, as in Listing 2.6 (Note: you'll need Listing 2.4 again).

Listing 2.6. Subclassing the Customer module.

package MyCust;
 require Customer; # Customer.pm must be in @INC
 @ISA = qw(Customer);
 sub search{
 my $self = shift;
 my $key = shift;
 defined($self->{$key}) ? return $self->{$key} : undef;
 }
 1;

Note how you use the @ISA array to imply that this class is a subclass of the Customer class. The @ISA array tells Perl that this package is an instance of the elements it contains, which usually correspond to other packages. In this case, MyCust is an instance of Customer. The only code you have to write is the search() method, and when the next release of Customer comes out, you are (theoretically) unaffected by any internal changes that have been made by the author.

Note:

Ordinarily, changes to the base class should not affect a subclass, unless the author changes the names of the methods or the structure of the object. Such changes are generally not a wise practice, once the class is considered stable and "out of alpha."


Now you can code your program to use the MyCust class instead of the base Customer class and have the additional functionality of the search() method, as shown in Listing 2.7 (this listing requires both Listing 2.4 and Listing 2.6):