📄 ch5.htm
字号:
example, if the object you are constructing will be writing a
log to disk, you would like to open the file it's writing to in
the constructor. (Of course, you would also have to remember to
close the file when the object is destroyed by placing the <TT><FONT FACE="Courier">close()</FONT></TT>
function call in the destructor.)
<P>
Here's what the constructor looks like for the <TT><FONT FACE="Courier">Cocoa.pm</FONT></TT>
module:
<HR>
<BLOCKQUOTE>
<B>Listing 5.4. Expanding the constructor.<BR>
</B>
</BLOCKQUOTE>
<BLOCKQUOTE>
<TT><FONT FACE="Courier">1 sub new {<BR>
2 my $this = {};<BR>
3 print "\n /* \n ** Created by Cocoa.pm
\n ** Use at own risk";<BR>
4 print "\n ** Did this code even
get past the javac compiler? ";<BR>
5 print "\n **/ \n";<BR>
6 bless $this;<BR>
7 return $this;<BR>
8 }</FONT></TT>
</BLOCKQUOTE>
<HR>
<P>
The output from running the test script (called <TT><FONT FACE="Courier">testme</FONT></TT>)
on this bare bones class would look like this:
<BLOCKQUOTE>
<TT><FONT FACE="Courier"> /*<BR>
** Created by Cocoa.pm<BR>
** Use at own risk<BR>
** Did this code even get past the javac compiler?<BR>
**/</FONT></TT>
</BLOCKQUOTE>
<P>
Now, regardless of which of these three methods you used to create
the <TT><FONT FACE="Courier">Cocoa</FONT></TT> object, you should
see the same output.
<P>
Some comments have been added at the start of the file with some
<TT><FONT FACE="Courier">print</FONT></TT> statements. You can
just as easily call other functions in or outside of the package
to get more initialization functionality. You should allow any
given class to be inherited, however. You should be able to call
the <TT><FONT FACE="Courier">new</FONT></TT> operator with the
class name as the first parameter. This ability to parse the class
name from the first argument causes the class to be inherited.
Thus, the new function becomes more or less like the function
shown in Listing 5.5.
<HR>
<BLOCKQUOTE>
<B>Listing 5.5. The improved </B><TT><B><FONT FACE="Courier">new()</FONT></B></TT><B>
function with class name recognition.<BR>
</B>
</BLOCKQUOTE>
<BLOCKQUOTE>
<TT><FONT FACE="Courier">1 sub new {<BR>
2 my $class = shift; #
Get the request class name<BR>
3 my $this = {};<BR>
4 bless $this, $class
# Use class name to bless() reference<BR>
5 $this->doInitialization();<BR>
6 return $this;<BR>
7 }</FONT></TT>
</BLOCKQUOTE>
<HR>
<P>
However, this method will force your class users to make calls
in one of three ways:
<UL>
<LI><TT><FONT FACE="Courier">Cocoa::new()</FONT></TT>
<LI><TT><FONT FACE="Courier">Cocoa->new()</FONT></TT>
<LI><TT><FONT FACE="Courier">new Cocoa;</FONT></TT>
</UL>
<P>
What if you wanted to use a reference to the object instead, such
as <TT><FONT FACE="Courier">$obj->new()</FONT></TT>? The <TT><FONT FACE="Courier">doInitialization()</FONT></TT>
method used will be of whatever <TT><FONT FACE="Courier">$class</FONT></TT>
the object is blessed into. Listing 5.6 uses the function call
<TT><FONT FACE="Courier">ref()</FONT></TT> to determine if the
class exists per se. The <TT><FONT FACE="Courier">ref()</FONT></TT>
function returns <TT><FONT FACE="Courier">true</FONT></TT> if
the item passed to it is a reference and <TT><FONT FACE="Courier">null</FONT></TT>
if not a reference. In the case of classes, the <TT><FONT FACE="Courier">true</FONT></TT>
value returned from the <TT><FONT FACE="Courier">ref()</FONT></TT>
function is the name of the class.
<HR>
<BLOCKQUOTE>
<B>Listing 5.6. The </B><TT><B><FONT FACE="Courier">new()</FONT></B></TT><B>
function with the capability to inherit classes.<BR>
</B>
</BLOCKQUOTE>
<BLOCKQUOTE>
<TT><FONT FACE="Courier"> 1 sub new {<BR>
2 my $this = shift; #
Get the class name<BR>
3
my $class = ref($this) || $this; <BR>
</FONT></TT><FONT FACE="ZapfDingbats">Â</FONT><TT><FONT FACE="Courier"> #
If class exists, use it else use reference.<BR>
4
my $this = {};<BR>
5 <BR>
6
bless $this, $class<BR>
7 $this->doInitialization();
<BR>
8 <BR>
9 return $this;<BR>
10 }</FONT></TT>
</BLOCKQUOTE>
<HR>
<P>
Within the class package, the methods typically deal with the
reference as an ordinary reference. Outside the class package,
the reference is generally treated as an opaque value that may
only be accessed through the class's methods. You can access the
values within a package directly, but it's not a good idea to
do so because such access defeats the whole purpose of object
orientation.
<P>
It's possible to bless a reference object more than once. However,
the caveat to such a task is that the new class must get rid of
the object at the previously blessed reference. For C and Pascal
programmers, this is like assigning a pointer to <TT><FONT FACE="Courier">malloc</FONT></TT>-ed
memory and then assigning the same pointer to another location
without freeing the previous location. In effect, a Perl object
must belong to one and only one class at a time.
<P>
So what's the real difference between an object and a reference?
Perl objects are blessed to belong to a class. References are
not blessed; if they are, they belong to a class and are objects.
Objects know to which class they belong. References do not have
a class, as such, to which they belong.
<H3><A NAME="InstanceVariables">Instance Variables</A></H3>
<P>
The arguments to a <TT><FONT FACE="Courier">new()</FONT></TT>
function for a constructor are called <I>instance variables</I>.
Instance variables are used for initializing each instance of
an object as it is created. For example, the <TT><FONT FACE="Courier">new()</FONT></TT>
function could expect a name for each new instance of an object
created. Using instance variables allows the customization of
each object as it is created.
<P>
Either an anonymous array or an anonymous hash can be used to
hold instance variables. To use a hash to store the parameters
coming in, you would use code similar to what is shown in Listing
5.7.
<HR>
<BLOCKQUOTE>
<B>Listing 5.7. Using instance variables.<BR>
</B>
</BLOCKQUOTE>
<BLOCKQUOTE>
<TT><FONT FACE="Courier">1 sub new {<BR>
2 my $type
= shift;<BR>
3 my %parm
= @_;<BR>
4 my $this
= {};<BR>
5 $this->{'Name'}
= $parm{'Name'};<BR>
6 $this->{'x'} =
$parm{'x'};<BR>
7 $this->{'y'} =
$parm{'y'};<BR>
8 bless $this,
$type;<BR>
9 }</FONT></TT>
</BLOCKQUOTE>
<HR>
<P>
You can also use an array instead of a hash to store the instance
variables. See Listing 5.8 for an example.
<HR>
<BLOCKQUOTE>
<B>Listing 5.8. Using hashes for instance variables.<BR>
</B>
</BLOCKQUOTE>
<BLOCKQUOTE>
<TT><FONT FACE="Courier">1 sub new {<BR>
2 my $type
= shift;<BR>
3 my %parm
= @_;<BR>
4 my $this
= [];<BR>
5 $this->[0]
= $parm{'Name'};<BR>
6 $this->[1]
= $parm{'x'};<BR>
7 $this->[2]
= $parm{'y'};<BR>
8 bless $this,
$type;<BR>
9 }</FONT></TT>
</BLOCKQUOTE>
<HR>
<P>
To construct an object, you can pass the parameters with the <TT><FONT FACE="Courier">new()</FONT></TT>
function call. For example, the call to create the <TT><FONT FACE="Courier">Cocoa</FONT></TT>
object becomes this:
<BLOCKQUOTE>
<TT><FONT FACE="Courier">$mug = Cocoa::new( 'Name' => 'top',
<BR>
'x' => 10,<BR>
'y' => 20 );</FONT></TT>
</BLOCKQUOTE>
<P>
The <TT><FONT FACE="Courier">=></FONT></TT> operator is just
like the comma operator, although it's a bit more readable. You
can write this code with commas instead of the <TT><FONT FACE="Courier">=></FONT></TT>
operator if that's what you prefer.
<P>
To access the variables as you would any other data members, you
can use the following statements:
<BLOCKQUOTE>
<TT><FONT FACE="Courier">print "Name=$mug->{'Name'}\n";
<BR>
print "x=$mug->{'x'}\n";<BR>
<BR>
print "y=$mug->{'y'}\n";</FONT></TT>
</BLOCKQUOTE>
<H2><A NAME="Methods"><FONT SIZE=5 COLOR=#FF0000>Methods</FONT></A>
</H2>
<P>
A method in a Perl class is simply a Perl subroutine. Perl doesn't
provide any special syntax for method definition. A method expects
its first argument to be the object or package on which it is
being invoked. Perl has just two types of methods: static and
virtual.
<P>
A <I>static</I> method expects a class name as the first argument.
A <I>virtual</I> <FONT SIZE=1> </FONT>method expects a reference
to an object as the first argument. Therefore, the way each method
handles the first argument determines whether the method is static
or virtual.
<P>
A static method applies functionality to the class as a whole
because it uses the name of the class. Therefore, functionality
in static methods is applicable to all objects of the class. Generally,
static methods ignore the first argument because they already
know which class they are in. Therefore, constructors are static
methods.
<P>
A virtual method expects a reference to an object as its first
argument. Typically the first thing a virtual method does is to
shift the first argument to a <TT><FONT FACE="Courier">self</FONT></TT>
or <TT><FONT FACE="Courier">this</FONT></TT> variable; it then
uses that shifted value as an ordinary reference. For example,
consider the code in Listing 5.9.
<HR>
<BLOCKQUOTE>
<B>Listing 5.9. Listing data items in a class.<BR>
</B>
</BLOCKQUOTE>
<BLOCKQUOTE>
<TT><FONT FACE="Courier">1 sub nameLister {<BR>
2 my $this = shift;<BR>
3 my ($keys ,$value );<BR>
4 while (($key, $value) = each (%$this))
{<BR>
5 print "\t$key
is $value.\n";<BR>
6 }<BR>
7 }</FONT></TT>
</BLOCKQUOTE>
<HR>
<P>
Line 2 in this listing is where the <TT><FONT FACE="Courier">$this</FONT></TT>
variable is set to point to the object. In line 4, the <TT><FONT FACE="Courier">$this</FONT></TT>
array is dereferenced at every <TT><FONT FACE="Courier">$key</FONT></TT>
location.
<H2><A NAME="ExportingMethodswithExporterpm"><FONT SIZE=5 COLOR=#FF0000>Exporting
Methods with </FONT><TT><FONT SIZE=5 COLOR=#FF0000 FACE="Courier">Exporter.pm</FONT></TT></A>
</H2>
<P>
If you tried to invoke the <TT><FONT FACE="Courier">Cocoa.pm</FONT></TT>
package right now, you would get an error message from Perl at
compile time about the methods not being found. This is because
the <TT><FONT FACE="Courier">Cocoa.pm</FONT></TT> methods have
not been exported. To export these functions, you need the <TT><FONT FACE="Courier">Exporter</FONT></TT>
module. This is done by adding the following lines to the start
of code in the package:
<BLOCKQUOTE>
<TT><FONT FACE="Courier">require Exporter;<BR>
@ISA = qw(Exporter);</FONT></TT>
</BLOCKQUOTE>
<P>
These two lines force the inclusion of the <TT><FONT FACE="Courier">Exporter.pm</FONT></TT>
module and then set the <TT><FONT FACE="Courier">@ISA</FONT></TT>
array with the name of the <TT><FONT FACE="Courier">Exporter</FONT></TT>
class for which to look.
<P>
To export your own class methods, you would have to list them
in the <TT><FONT FACE="Courier">@EXPORT</FONT></TT> array. For
example, to export the <TT><FONT FACE="Courier">closeMain</FONT></TT>
and <TT><FONT FACE="Courier">declareMain</FONT></TT> methods,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -