📄 perltoot.1
字号:
.PP.Vb 10\& sub debug {\& my $self = shift;\& confess "usage: thing\->debug(level)" unless @_ == 1;\& my $level = shift;\& if (ref($self)) {\& $self\->{"_DEBUG"} = $level; # just myself\& } else {\& $Debugging = $level; # whole class\& }\& }\&\& sub DESTROY {\& my $self = shift;\& if ($Debugging || $self\->{"_DEBUG"}) {\& carp "Destroying $self " . $self\->name;\& }\& \-\- ${ $self\->{"_CENSUS"} };\& }.Ve.PPWhat happens if a derived class (which we'll call Employee) inheritsmethods from this Person base class? Then \f(CW\*(C`Employee\->debug()\*(C'\fR, when calledas a class method, manipulates \f(CW$Person::Debugging\fR not \f(CW$Employee::Debugging\fR..Sh "Class Destructors".IX Subsection "Class Destructors"The object destructor handles the death of each distinct object. But sometimesyou want a bit of cleanup when the entire class is shut down, whichcurrently only happens when the program exits. To make such a\&\fIclass destructor\fR, create a function in that class's package named\&\s-1END\s0. This works just like the \s-1END\s0 function in traditional modules,meaning that it gets called whenever your program exits unless it execsor dies of an uncaught signal. For example,.PP.Vb 5\& sub END {\& if ($Debugging) {\& print "All persons are going away now.\en";\& }\& }.Ve.PPWhen the program exits, all the class destructors (\s-1END\s0 functions) arebe called in the opposite order that they were loaded in (\s-1LIFO\s0 order)..Sh "Documenting the Interface".IX Subsection "Documenting the Interface"And there you have it: we've just shown you the \fIimplementation\fR of thisPerson class. Its \fIinterface\fR would be its documentation. Usually thismeans putting it in pod (\*(L"plain old documentation\*(R") format right therein the same file. In our Person example, we would place the followingdocs anywhere in the Person.pm file. Even though it looks mostly likecode, it's not. It's embedded documentation such as would be used bythe pod2man, pod2html, or pod2text programs. The Perl compiler ignorespods entirely, just as the translators ignore code. Here's an example ofsome pods describing the informal interface:.PP.Vb 1\& =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.....Ve.PPThat's all there is to the matter of interface versus implementation.A programmer who opens up the module and plays around with all the privatelittle shiny bits that were safely locked up behind the interface contracthas voided the warranty, and you shouldn't worry about their fate..SH "Aggregation".IX Header "Aggregation"Suppose you later want to change the class to implement better names.Perhaps you'd like to support both given names (called Christian names,irrespective of one's religion) and family names (called surnames), plusnicknames and titles. If users of your Person class have been properlyaccessing it through its documented interface, then you can easily changethe underlying implementation. If they haven't, then they lose andit's their fault for breaking the contract and voiding their warranty..PPTo do this, we'll make another class, this one called Fullname. What'sthe Fullname class look like? To answer that question, you have tofirst figure out how you want to use it. How about we use it this way:.PP.Vb 7\& $him = Person\->new();\& $him\->fullname\->title("St");\& $him\->fullname\->christian("Thomas");\& $him\->fullname\->surname("Aquinas");\& $him\->fullname\->nickname("Tommy");\& printf "His normal name is %s\en", $him\->name;\& printf "But his real name is %s\en", $him\->fullname\->as_string;.Ve.PPOk. To do this, we'll change \fIPerson::new()\fR so that it supportsa full name field this way:.PP.Vb 11\& sub new {\& my $class = shift;\& my $self = {};\& $self\->{FULLNAME} = Fullname\->new();\& $self\->{AGE} = undef;\& $self\->{PEERS} = [];\& $self\->{"_CENSUS"} = \e$Census;\& bless ($self, $class);\& ++ ${ $self\->{"_CENSUS"} };\& return $self;\& }\&\& sub fullname {\& my $self = shift;\& return $self\->{FULLNAME};\& }.Ve.PPThen to support old code, define \fIPerson::name()\fR this way:.PP.Vb 5\& sub name {\& my $self = shift;\& return $self\->{FULLNAME}\->nickname(@_)\& || $self\->{FULLNAME}\->christian(@_);\& }.Ve.PPHere's the Fullname class. We'll use the same techniqueof using a hash reference to hold data fields, and methodsby the appropriate name to access them:.PP.Vb 2\& package Fullname;\& use strict;\&\& sub new {\& my $class = shift;\& my $self = {\& TITLE => undef,\& CHRISTIAN => undef,\& SURNAME => undef,\& NICK => undef,\& };\& bless ($self, $class);\& return $self;\& }\&\& sub christian {\& my $self = shift;\& if (@_) { $self\->{CHRISTIAN} = shift }\& return $self\->{CHRISTIAN};\& }\&\& sub surname {\& my $self = shift;\& if (@_) { $self\->{SURNAME} = shift }\& return $self\->{SURNAME};\& }\&\& sub nickname {\& my $self = shift;\& if (@_) { $self\->{NICK} = shift }\& return $self\->{NICK};\& }\&\& sub title {\& my $self = shift;\& if (@_) { $self\->{TITLE} = shift }\& return $self\->{TITLE};\& }\&\& sub as_string {\& my $self = shift;\& my $name = join(" ", @$self{\*(AqCHRISTIAN\*(Aq, \*(AqSURNAME\*(Aq});\& if ($self\->{TITLE}) {\& $name = $self\->{TITLE} . " " . $name;\& }\& return $name;\& }\&\& 1;.Ve.PPFinally, here's the test program:.PP.Vb 4\& #!/usr/bin/perl \-w\& use strict;\& use Person;\& sub END { show_census() }\&\& sub show_census () {\& printf "Current population: %d\en", Person\->population;\& }\&\& Person\->debug(1);\&\& show_census();\&\& my $him = Person\->new();\&\& $him\->fullname\->christian("Thomas");\& $him\->fullname\->surname("Aquinas");\& $him\->fullname\->nickname("Tommy");\& $him\->fullname\->title("St");\& $him\->age(1);\&\& printf "%s is really %s.\en", $him\->name, $him\->fullname\->as_string;\& printf "%s\*(Aqs age: %d.\en", $him\->name, $him\->age;\& $him\->happy_birthday;\& printf "%s\*(Aqs age: %d.\en", $him\->name, $him\->age;\&\& show_census();.Ve.SH "Inheritance".IX Header "Inheritance"Object-oriented programming systems all support some notion ofinheritance. Inheritance means allowing one class to piggy-back ontop of another one so you don't have to write the same code again andagain. It's about software reuse, and therefore related to Laziness,the principal virtue of a programmer. (The import/export mechanisms intraditional modules are also a form of code reuse, but a simpler one thanthe true inheritance that you find in object modules.).PPSometimes the syntax of inheritance is built into the core of thelanguage, and sometimes it's not. Perl has no special syntax forspecifying the class (or classes) to inherit from. Instead, it's allstrictly in the semantics. Each package can have a variable called \f(CW@ISA\fR,which governs (method) inheritance. If you try to call a method on anobject or class, and that method is not found in that object's package,Perl then looks to \f(CW@ISA\fR for other packages to go looking through insearch of the missing method..PPLike the special per-package variables recognized by Exporter (such as\&\f(CW@EXPORT\fR, \f(CW@EXPORT_OK\fR, \f(CW@EXPORT_FAIL\fR, \f(CW%EXPORT_TAGS\fR, and \f(CW$VERSION\fR), the \f(CW@ISA\fRarray \fImust\fR be a package-scoped global and not a file-scoped lexicalcreated via \fImy()\fR. Most classes have just one item in their \f(CW@ISA\fR array.In this case, we have what's called \*(L"single inheritance\*(R", or \s-1SI\s0 for short..PPConsider this class:.PP.Vb 4\& package Employee;\& use Person;\& @ISA = ("Person");\& 1;.Ve.PPNot a lot to it, eh? All it's doing so far is loading in anotherclass and stating that this one will inherit methods from thatother class if need be. We have given it none of its own methods.We rely upon an Employee to behave just like a Person..PPSetting up an empty class like this is called the \*(L"empty subclass test\*(R";that is, making a derived class that does nothing but inherit from abase class. If the original base class has been designed properly,then the new derived class can be used as a drop-in replacement for theold one. This means you should be able to write a program like this:.PP.Vb 5\& use Employee;\& my $empl = Employee\->new();\& $empl\->name("Jason");\& $empl\->age(23);\& printf "%s is age %d.\en", $empl\->name, $empl\->age;.Ve.PPBy proper design, we mean always using the two-argument form of \fIbless()\fR,avoiding direct access of global data, and not exporting anything. If youlook back at the \fIPerson::new()\fR function we defined above, we were carefulto do that. There's a bit of package data used in the constructor,but the reference to this is stored on the object itself and all othermethods access package data via that reference, so we should be ok..PPWhat do we mean by the \fIPerson::new()\fR function \*(-- isn't that actuallya method? Well, in principle, yes. A method is just a function thatexpects as its first argument a class name (package) or object(blessed reference). \fIPerson::new()\fR is the function that both the\&\f(CW\*(C`Person\->new()\*(C'\fR method and the \f(CW\*(C`Employee\->new()\*(C'\fR method endup calling. Understand that while a method call looks a lot like afunction call, they aren't really quite the same, and if you treat themas the same, you'll very soon be left with nothing but broken programs.First, the actual underlying calling conventions are different: methodcalls get an extra argument. Second, function calls don't do inheritance,but methods do..PP.Vb 4\& Method Call Resulting Function Call\& \-\-\-\-\-\-\-\-\-\-\- \-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\& Person\->new() Person::new("Person")\& Employee\->new() Person::new("Employee").Ve.PPSo don't use function calls when you mean to call a method..PPIf an employee is just a Person, that's not all too very interesting.So let's add some other methods. We'll give our employeedata fields to access their salary, their employee \s-1ID\s0, and theirstart date..PPIf you're getting a little tired of creating all these nearly identicalmethods just to get at the object's data, do not despair. Later,we'll describe several different convenience mechanisms for shorteningthis up. Meanwhile, here's the straight-forward way:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -