?? ch14.htm
字號:
fuNCtion works outside the object-oriented world.
<H3><A NAME="ExampleInitializingProperties">
Example: Initializing Properties</A></H3>
<P>
You now know how to instantiate a new class by using a <TT>new()</TT>
fuNCtion and how to create class properties (the class information)
with undefined values. Let's look at how to give those properties
some real values. You need to start by looking at the <TT>new()</TT>
fuNCtion from Listing 14.1. It's repeated here so you don't need
to flip back to look for it.
<BLOCKQUOTE>
<PRE>
sub new {
my($class) = shift;
bless {
"PART_NUM" => undef,
"QTY_ON_HAND" => undef
}, $class;
}
</PRE>
</BLOCKQUOTE>
<P>
The <TT>new()</TT> fuNCtion is a <I>static
</I>method. Static methods are not associated with any specific
object. This makes sense because the <TT>new()</TT>
fuNCtion is designed to create objects. It can't be associated
with an object that doesn't exist yet, can it?
<P>
The first argument to a static method is always the class name.
Perl takes the name of the class from in front of the -> operator
and adds it to the beginning of the parameter array, which is
passed to the <TT>new()</TT> fuNCtion.
<P>
If you want to pass two values into the <TT>new()</TT>
fuNCtion to initialize the class properties, you can modify the
method to look for additional arguments as in the following:
<BLOCKQUOTE>
<PRE>
sub new {
my($class) = shift;
my($partNum) = shift;
my($qty) = shift;
bless {
"PART_NUM" => $partNum,
"QTY_ON_HAND" => $qty
}, $class;
}
</PRE>
</BLOCKQUOTE>
<P>
Each parameter you expect to see gets shifted out of the parameter
array into a scalar variable. Then the scalar variable is used
to initialize the anonymous hash.
<P>
You invoke this updated version of <TT>new()</TT>
by using this line of code:
<BLOCKQUOTE>
<PRE>
$item = Inventory_item->new("AW-30", 1200);
</PRE>
</BLOCKQUOTE>
<P>
While this style of parameter passing is very serviceable, Perl
provides for the use of another technique: passing named parameters.
<H3><A NAME="ExampleUsingNamedParametersinConstructors">
Example: Using Named Parameters in Constructors</A></H3>
<P>
The coNCept of using named parameters has been quickly accepted
in new computer languages. I was first introduced to it while
working with the scripting language for Microsoft Word. Rather
than explain the technique in words, let me show you an example
in code, as shown in Listing 14.2. I think you'll understand the
value of this technique very quickly.
<P>
<IMG SRC="pseudo.gif" tppabs="http://cheminf.nankai.edu.cn/~eb~/Perl%205%20By%20Example/pseudo.gif" BORDER=1 ALIGN=RIGHT><p>
<BLOCKQUOTE>
<I>Start a definition of the </I><TT><I>Inventory_item</I></TT><I>
class.<BR>
Define the constructor for the class.<BR>
Get the name of the class from the parameter array.<BR>
Assign the rest of the parameters to the </I><TT><I>%params</I></TT><I>
hash.<BR>
Bless the anonymous hash with the class name.<BR>
Use </I><TT><I>%params</I></TT><I>
to initialize the class properties.<BR>
Start the </I><TT><I>main</I></TT><I>
namespace.<BR>
Call the constructor for the </I><TT><I>Inventory_item</I></TT><I>
class.<BR>
Assign the object refereNCe to </I><TT><I>$item</I></TT><I>.
<BR>
Print the two property values to verify that the property initialization
worked.</I>
</BLOCKQUOTE>
<HR>
<BLOCKQUOTE>
<B>Listing 14.2 14LST02.PL-Setting Class Properties
Using the Class Constructor<BR>
</B>
</BLOCKQUOTE>
<BLOCKQUOTE>
<PRE>
package Inventory_item;
sub new {
my($class) = shift;
my(%params) = @_;
bless {
"PART_NUM" => $params{"PART_NUM"},
"QTY_ON_HAND" => $params{"QTY_ON_HAND"}
}, $class;
}
package main;
$item = Inventory_item->new(
"PART_NUM" => "12A-34",
"QTY_ON_HAND" => 34);
print("The part number is " . %{$item}->{'PART_NUM'} . "\n");
print("The quantity is " . %{$item}->{'QTY_ON_HAND'} . "\n");
</PRE>
</BLOCKQUOTE>
<HR>
<P>
One key statement to understand is the line in which the <TT>new()</TT>
fuNCtion is called:
<BLOCKQUOTE>
<PRE>
$item = Inventory_item->new(
"PART_NUM" => "12A-34",
"QTY_ON_HAND" => 34);
</PRE>
</BLOCKQUOTE>
<P>
This looks like an associative array is being passed as the parameter
to <TT>new()</TT>, but looks are deceiving
in this case. The <TT>=></TT> operator
does exactly the same thing as the comma operator. Therefore,
the preceding statement is identical to the following:
<BLOCKQUOTE>
<PRE>
$item = Inventory_item->new("PART_NUM", "12A-34", "QTY_ON_HAND", 34);
</PRE>
</BLOCKQUOTE>
<P>
Also, a four-element array is being passed to<TT>
new()</TT>.
<P>
The second line of the <TT>new()</TT>
fuNCtion, <TT>my(%params) = @_;</TT>
does something very interesting. It takes the four-element array
and turns it into a hash with two entries. One entry is for <TT>PART_NUM</TT>,
and the other is for <TT>QTY_ON_HAND</TT>.
<P>
This conversion (array into hash) lets you access the parameters
by name using <TT>%params</TT>. The
initialization of the anonymous hash-inside the <TT>bless()</TT>
fuNCtion-takes advantage of this by using expressions such as
<TT>$params{"PART_NUM"}</TT>.
<P>
I feel that this technique helps to create self-documenting code.
When looking at the script, you always know which property is
being referred to. In addition, you can also use this technique
to partially initialize the anonymous hash. For example,
<BLOCKQUOTE>
<PRE>
$item = Inventory_item->new("QTY_ON_HAND" => 34);
</PRE>
</BLOCKQUOTE>
<P>
gives a value only to the <TT>QTY_ON_HAND</TT>
property; the <TT>PART_NUM</TT> property
will remain undefined. You can use this technique with any type
of fuNCtion, not just constructors.
<H3><A NAME="ExampleInheritaNCePerlStyle">
Example: InheritaNCe, Perl Style</A></H3>
<P>
You already know that inheritaNCe means that properties and methods
of a parent class will be available to child classes. This section
shows you can use inheritaNCe in Perl.
<P>
First, a little diversion. You may not have realized it yet, but
each package can have its own set of variables that won't interfere
with another package's set. So if the variable <TT>$first</TT>
was defined in package A, you could also define <TT>$first</TT>
in package B without a conflict arising. For example,
<BLOCKQUOTE>
<PRE>
package A;
$first = "package A";
package B;
$first = "package B";
package main;
print("$A::first\n");
print("$B::first\n");
</PRE>
</BLOCKQUOTE>
<P>
displays
<BLOCKQUOTE>
<PRE>
package A
package B
</PRE>
</BLOCKQUOTE>
<P>
Notice that the <TT>::</TT> is being
used as a scope resolution operator in this example. The <TT>-></TT>
notation will not work; also, it's okay that <TT>-></TT>
can't be used because we're not really dealing with objects in
this example, just different namespaces.
<P>
You're probably wondering what this diversion has to do with inheritaNCe,
right? Well, inheritaNCe is accomplished by placing the names
of parent classes into a special array called <TT>@ISA</TT>.
The elements of <TT>@ISA</TT> are
searched left to right for any missing methods. In addition, the
<TT>UNIVERSAL</TT> class is invisibly
tacked on to the end of the search list. For example,
<BLOCKQUOTE>
<PRE>
package UNIVERSAL;
sub AUTOLOAD {
die("[Error: Missing FuNCtion] $AUTOLOAD @_\n");
}
package A;
sub foo {
print("Inside A::foo\n");
}
package B;
@ISA = (A);
package main;
B->foo();
B->bar();
</PRE>
</BLOCKQUOTE>
<P>
displays
<BLOCKQUOTE>
<PRE>
Inside A::foo
[Error: Missing FuNCtion] B::bar B
</PRE>
</BLOCKQUOTE>
<P>
Let's start with the nearly empty class <TT>B</TT>.
This class has no properties or methods; it just has a parent:
the <TT>A</TT> class. When Perl executes
<TT>B->foo()</TT>, the first line
in the main package, it first looks in <TT>B</TT>.
When the <TT>foo()</TT> fuNCtion is
not found, it looks to the <TT>@ISA</TT>
array. The first element in the array is <TT>A</TT>,
so Perl looks at the <TT>A</TT> class.
Because <TT>A</TT> does have a <TT>foo()</TT>
method, that method is executed.
<P>
When a method can't be found by looking at each element of the
<TT>@ISA</TT> array, the <TT>UNIVERSAL</TT>
class is checked. The second line of the main package, <TT>B->bar()</TT>,
tries to use a fuNCtion that is not defined in either the base
class <TT>B</TT> or the parent class
<TT>A</TT>. Therefore, as a last-ditch
effort, Perl looks in the <TT>UNIVERSAL</TT>
class. The <TT>bar()</TT> fuNCtion
is not there, but a special fuNCtion called <TT>AUTOLOAD()</TT>
is.
<P>
The <TT>AUTOLOAD()</TT> fuNCtion is
normally used to automatically load undefined fuNCtions. Its normal
use is a little beyond the scope of this book. However, in this
example, I have changed it into an error reporting tool. Instead
of loading undefined fuNCtions, it now causes the script to end
(via the <TT>die()</TT> fuNCtion)
and displays an error message indicating which method is undefined
and which class Perl was looking in. Notice that the message ends
with a newline to prevent Perl from printing the script name and
line number where the script death took place. In this case, the
information would be meaningless because the line number would
be inside the <TT>AUTOLOAD()</TT>
fuNCtion.
<P>
Listing 14.3 shows how to call the constructor of the parent class.
This example shows how to explicitly call the parent's constructor.
In the next section, you learn how to use the <TT>@ISA</TT>
array to generically call methods in the parent classes. However,
because constructors are frequently used to initialize properties,
I feel that they should always be called explicitly, which causes
less confusion when calling constructors from more than one parent.
<P>
This example also shows how to inherit the properties of a parent
class. By calling the parent class constructor fuNCtion, you can
initialize an anonymous hash that can be used by the base class
for adding additional properties.
<P>
<IMG SRC="pseudo.gif" tppabs="http://cheminf.nankai.edu.cn/~eb~/Perl%205%20By%20Example/pseudo.gif" BORDER=1 ALIGN=RIGHT><p>
<BLOCKQUOTE>
<I>Start a definition of the </I><TT><I>Inventory_item</I></TT><I>
class.<BR>
Define the constructor for the class.<BR>
Get the name of the class from the parameter array.<BR>
Assign the rest of the parameters to the </I><TT><I>%params</I></TT><I>
hash.<BR>
Bless the anonymous hash with the class name.<BR>
Use </I><TT><I>%params</I></TT><I>
to initialize the class properties.<BR>
Start a definition of the </I><TT><I>Pen</I></TT><I>
class.<BR>
Initialize the </I><TT><I>@ISA</I></TT><I>
array to define the parent classes.<BR>
Define the constructor for the class.<BR>
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -