📄 ch14.htm
字号:
errors. For example, if pens were sold in lots of 100, the <TT>changeQuantityOnHand()</TT>
fuNCtion would reflect this. Changing the quantity by only one
would not be possible. This enforcement of business rules is one
of the biggest attractions of object-oriented programming.
<H2><A NAME="HowPerlHandlesObjects"><FONT SIZE=5 COLOR=#FF0000>
How Perl Handles Objects</FONT></A></H2>
<P>
Remember the coNCept of refereNCes that was discussed in <A HREF="ch8.htm" tppabs="http://cheminf.nankai.edu.cn/~eb~/Perl%205%20By%20Example/ch8.htm">Chapter
8</a>, "RefereNCes"? If not, please re-read it. RefereNCes
will play a large role in the rest of the chapter and are critical
to understanding how classes are used. You specifically need to
remember that the <TT>{ }</TT> notation
indicates an anonymous hash. Armed with this knowledge and the
object-oriented terminology from the first part of this chapter,
you are ready to look at real Perl objects. Listing 14.1 shows
you how the <TT>inventory_item</TT>
class could be defined in Perl.
<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 new class called </I><TT><I>Inventory_item</I></TT><I>.
The </I><TT><I>package</I></TT><I>
keyword is used to introduce new classes and namespaces.<BR>
Define the </I><TT><I>new()</I></TT><I>
fuNCtion. This fuNCtion is responsible for constructing a new
object.<BR>
The first parameter to the </I><TT><I>new()</I></TT><I>
fuNCtion is the class name (</I><TT><I>Inventory_item</I></TT><I>).
This is explained further in the sections "Example: Initializing
Object Properties" and "Static Versus Regular Methods"
later in the chapter.<BR>
The </I><TT><I>bless()</I></TT><I>
fuNCtion is used to change the data type of the anonymous hash
to </I><TT><I>$class</I></TT><I> or
</I><TT><I>Inventory_item</I></TT><I>.
Because this is the last statement in the method, its value will
be returned as the value of the fuNCtion. I feel that using the
return statement to explicitly return a value would clutter the
code in this situation.<BR>
An anonymous hash is used to hold the properties for the class.
For the moment, their values are undefined. Assigning values to
properties is discussed in the section "Example: Initializing
Properties" later in this chapter.<BR>
Switch to the package called </I><TT><I>main</I></TT><I>.
This is the default place for variables and code to go (technically,
this is called a namespace). If no classes are defined in your
script, then this line is not needed.<BR>
Assign an instaNCe of the </I><TT><I>Inventory_item</I></TT><I>
class to the </I><TT><I>$item variable</I></TT><I>.</I>
</BLOCKQUOTE>
<HR>
<BLOCKQUOTE>
<B>Listing 14.1 14LST01.PL-Defining the </B><TT><B><FONT FACE="Courier">Inventory_item</FONT></B></TT><B>
Class<BR>
</B>
</BLOCKQUOTE>
<BLOCKQUOTE>
<PRE>
package Inventory_item;
sub new {
my($class) = shift;
bless {
"PART_NUM" => undef,
"QTY_ON_HAND" => undef
}, $class;
}
package main;
$item = Inventory_item->new();
</PRE>
</BLOCKQUOTE>
<HR>
<P>
There is a <I>lot</I> of new stuff in this small ten-line listing,
and you'll need to review it carefully to glean the information
needed to understand everything that is happening. You'll also
start to translate between the Perl keywords and the object-oriented
terminology.
<P>
The first line, <TT>package Inventory_item</TT>;
says two things, depending on if you are thinking in terms of
objects or in terms of Perl. When considering objects, it begins
the definition of a class. When considering Perl, it means that
a specific namespace will be used.
<P>
You read a little bit about namespace in <A HREF="ch3.htm" tppabs="http://cheminf.nankai.edu.cn/~eb~/Perl%205%20By%20Example/ch3.htm" >Chapter 3</A> "Variables."
A <I>namespace</I> is used to keep one set of names from interfering
with another. For example, you can have a variable named bar and
a fuNCtion called <TT>bar</TT>, and
the names will not conflict because variables and fuNCtions each
have their own namespace.
<P>
The <TT>package</TT> keyword lets
you create your own namespace. This lets you create more than
one fuNCtion called <TT>new()</TT>
as long as each is in its own package or namespace. If you need
to refer to a specific fuNCtion in a specific namespace, you can
use <TT>Inventory_item­>new</TT>,
<TT>Inventory_item::new</TT>, or <TT>Inventory_item'new</TT>.
Which notation you use will probably depend on your background.
Object-oriented folks will probably want to use the -> notation.
<P>
The second line, <TT>sub new</TT>,
starts the definition of a fuNCtion. It has become accepted practice
in the object-oriented world to construct new objects with the
<TT>new()</TT> method. This is called
the class <I>constructor</I>. This might be a good time to emphasize
that the class definition is a template. It's only when the <TT>new()</TT>
fuNCtion is called that an object is created or <I>instantiated</I>.
Instantiation means that memory is allocated from your computer's
memory pool and devoted to the use of this specific object. The
<TT>new()</TT> fuNCtion normally returns
a refereNCe to an anonymous hash. Therefore, the <TT>new()</TT>
fuNCtion should never be called unless you are assigning its return
value to a variable. If you don't store the refereNCe into a scalar
variable for later use, you'll never be able to access the anonymous
hash inside the object. For all intents and purposes, the anonymous
hash <I>is</I> the object.<BR>
<p>
<CENTER>
<TABLE BORDERCOLOR=#000000 BORDER=1 WIDTH=80%>
<TR><TD><B>Note</B></TD></TR>
<TR><TD>
<BLOCKQUOTE>
Not all objects are represented by hashes. If you need an object to emulate a gas tank, perhaps an anonymous scalar would be sufficient to hold the number of gallons of gas left in the tank. However, you'll see that working with hashes is quite easy oNCe
you learn how. Hashes give you tremendous flexibility to solve programming problems.</BLOCKQUOTE>
</TD></TR>
</TABLE>
</CENTER>
<P>
<P>
There is nothing magic about the new fuNCtion name. You could
call the fuNCtion that creates new objects <TT>create()</TT>
or <TT>build()</TT> or anything else,
but don't. The standard is <TT>new()</TT>,
and everyone who reads your program or uses your classes will
look for a <TT>new()</TT> fuNCtion.
If they don't find one, confusion might set in. There are so few
standards in the programming business. When they exist, it's usually
a good idea to follow them.
<P>
The <TT>bless()</TT> fuNCtion on the
third line changes the data type of its first parameter to the
string value of its second parameter. In the situation shown here,
the data type is changed to the name of the package, <TT>Inventory_item</TT>.
Using <TT>bless()</TT> to change the
data type of a refereNCe causes the <TT>ref()</TT>
fuNCtion to return the new data type. This potentially confusing
point is explained further in the section "Example: Bless
the Hash and Pass the RefereNCe" later in this chapter.<BR>
<p>
<CENTER>
<TABLE BORDERCOLOR=#000000 BORDER=1 WIDTH=80%>
<TR><TD><B>Note</B></TD></TR>
<TR><TD>
<BLOCKQUOTE>
I used the <TT>bless()</TT> fuNCtion without using parentheses to surround the parameters. While Perl lets you do this, I have been studiously using parentheses to avoid certain issues of precedeNCe that seem beyond the scope of this book. In this special
instaNCe, where the anonymous hash is one of the parameters, I feel that using parentheses clutters the source code.
</BLOCKQUOTE>
</TD></TR>
</TABLE>
</CENTER>
<P>
<P>
Embedded inside the <TT>bless()</TT>
fuNCtion call is the creation of an anonymous hash that holds
the properties of the class. The hash definition is repeated here
for your convenieNCe:
<BLOCKQUOTE>
<PRE>
{
"PART_NUM" => undef,
"QTY_ON_HAND" => undef
};
</PRE>
</BLOCKQUOTE>
<P>
Nothing significant is happening here that you haven't seen before.
Each entry in the hash is a different property of the class. For
the moment, I have assigned the undefined value to the value part
of the entries. Soon you'll see how to properly initialize them.
<P>
After the <TT>new()</TT> fuNCtion
is defined, there is another package statement:
<BLOCKQUOTE>
<PRE>
package main;
</PRE>
</BLOCKQUOTE>
<P>
There is no object-oriented way to interpret this statement. It
simply tells Perl to switch back to using the <TT>main</TT>
namespace. Don't be fooled into thinking that there is a <TT>main</TT>
class somewhere. There isn't.<BR>
<p>
<CENTER>
<TABLE BORDERCOLOR=#000000 BORDER=1 WIDTH=80%>
<TR><TD><B>Caution</B></TD></TR>
<TR><TD>
<BLOCKQUOTE>
While you could create a <TT>main</TT> class by defining the <TT>new()</TT> fuNCtion after the <TT>package main;</TT> statement, things might get to be confusing, so don't do it!
</BLOCKQUOTE>
</TD></TR>
</TABLE>
</CENTER>
<P>
<P>
The last statement in the file is really the first line that gets
executed. Everything else in the script has been class and method
definitions.
<BLOCKQUOTE>
<PRE>
$item = Inventory_item->new();
</PRE>
</BLOCKQUOTE>
<P>
By now, you've probably guessed what this statement does. It assigns
a refereNCe to the anonymous hash to <TT>$item</TT>.
You can derefereNCe <TT>$item</TT>
in order to determine the value of the entries in the hash. If
you use the <TT>ref()</TT> fuNCtion
to determine the data type of <TT>$item</TT>,
you find that its value is <TT>Inventory_item</TT>.
<P>
Here are some key items to remember about objects in Perl:
<BLOCKQUOTE>
<B>All objects are anonymous hashes:</B> While not strictly true,
perhaps it should be. Also, most of the examples in this book
follow this rule. This means that most of the <TT>new()</TT>
methods you see return a refereNCe to a hash.
</BLOCKQUOTE>
<BLOCKQUOTE>
<TT><B><FONT FACE="Courier">bless()</FONT></B></TT><B> changes
the data type of the anonymous hash:</B> The data type is changed
to the name of the class.
</BLOCKQUOTE>
<BLOCKQUOTE>
<B>The anonymous hash itself is blessed:</B> This means that refereNCes
to the hash are not blessed. This coNCept is probably a little
uNClear. I had trouble figuring it out myself. The next section
clarifies this point and uses an example.
</BLOCKQUOTE>
<BLOCKQUOTE>
<B>Objects can belong to only one class at a time:</B> You can
use the <TT>bless()</TT> fuNCtion
to change the ownership at any time. However, don't do this unless
you have a good reason.
</BLOCKQUOTE>
<BLOCKQUOTE>
<B>The </B><TT><B><FONT FACE="Courier">-></FONT></B></TT><B>
operator is used to call a method associated with a class:</B>
There are two different ways to invoke or call class methods:
</BLOCKQUOTE>
<BLOCKQUOTE>
<PRE>
$item = new Inventory_item;
</PRE>
</BLOCKQUOTE>
<P>
or
<BLOCKQUOTE>
<PRE>
$item = Inventory_item->new();
</PRE>
</BLOCKQUOTE>
<P>
Both of these techniques are equivalent, but the <TT>-></TT>
style is preferred by object-oriented folks.
<H3><A NAME="ExampleBlesstheHashandPasstheRefereNCe">
Example: Bless the Hash and Pass the RefereNCe</A></H3>
<P>
If you recall from <A HREF="ch8.htm" tppabs="http://cheminf.nankai.edu.cn/~eb~/Perl%205%20By%20Example/ch8.htm" >Chapter 8</A> the <TT>ref()</TT>
fuNCtion returns either the undefined value or a string indicating
the parameter's data type (<TT>SCALAR</TT>,
<TT>ARRAY</TT>, <TT>HASH</TT>,
<TT>CODE</TT>, or <TT>REF</TT>).
When classes are used, these data types don't provide enough information.
<P>
This is why the <TT>bless()</TT> fuNCtion
was added to the language. It lets you change the data type of
any variable. You can change the data type to any string value
you like. Most often, the data type is changed to reflect the
class name.
<P>
It is important to understand that the variable itself will have
its data type changed. The following lines of code should make
this clear:
<BLOCKQUOTE>
<PRE>
$foo = { };
$fooRef = $foo;
print("data of \$foo is " . ref($foo) . "\n");
print("data of \$fooRef is " . ref($fooRef) . "\n");
bless($foo, "Bar");
print("data of \$foo is " . ref($foo) . "\n");
print("data of \$fooRef is " . ref($fooRef) . "\n");
</PRE>
</BLOCKQUOTE>
<P>
This program displays the following:
<BLOCKQUOTE>
<PRE>
data of $foo is HASH
data of $fooRef is HASH
data of $foo is Bar
data of $fooRef is Bar
</PRE>
</BLOCKQUOTE>
<P>
After the data type is changed, the <TT>ref($fooRef)</TT>
fuNCtion call returns <TT>Bar</TT>
instead of the old value of <TT>HASH</TT>.
This can happen only if the variable itself has been altered.
This example also shows that the <TT>bless()</TT>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -