⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ch14.htm

📁 prrl 5 programs codes in the book
💻 HTM
📖 第 1 页 / 共 5 页
字号:

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 {

            &quot;PART_NUM&quot;    =&gt; undef,

            &quot;QTY_ON_HAND&quot; =&gt; 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 -&gt; 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 {

            &quot;PART_NUM&quot;    =&gt; $partNum,

            &quot;QTY_ON_HAND&quot; =&gt; $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-&gt;new(&quot;AW-30&quot;, 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&nbsp;&nbsp;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 {

            &quot;PART_NUM&quot;    =&gt; $params{&quot;PART_NUM&quot;},

            &quot;QTY_ON_HAND&quot; =&gt; $params{&quot;QTY_ON_HAND&quot;}

            }, $class;

    }



package main;



    $item = Inventory_item-&gt;new(

&quot;PART_NUM&quot;    =&gt; &quot;12A-34&quot;,

&quot;QTY_ON_HAND&quot; =&gt; 34);



    print(&quot;The part number is &quot; . %{$item}-&gt;{'PART_NUM'} . &quot;\n&quot;);

    print(&quot;The quantity is &quot; . %{$item}-&gt;{'QTY_ON_HAND'} . &quot;\n&quot;);

</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-&gt;new(

&quot;PART_NUM&quot;    =&gt; &quot;12A-34&quot;,

               &quot;QTY_ON_HAND&quot; =&gt; 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>=&gt;</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-&gt;new(&quot;PART_NUM&quot;, &quot;12A-34&quot;, &quot;QTY_ON_HAND&quot;, 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{&quot;PART_NUM&quot;}</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-&gt;new(&quot;QTY_ON_HAND&quot; =&gt; 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 = &quot;package A&quot;;



package B;

    $first = &quot;package B&quot;;



package main;

    print(&quot;$A::first\n&quot;);

    print(&quot;$B::first\n&quot;);

</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>-&gt;</TT>

notation will not work; also, it's okay that <TT>-&gt;</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(&quot;[Error: Missing FuNCtion] $AUTOLOAD @_\n&quot;);

    }





package A;

    sub foo {

        print(&quot;Inside A::foo\n&quot;);

    }



package B;

    @ISA = (A);



package main;

    B-&gt;foo();

    B-&gt;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-&gt;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-&gt;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 + -