📄 ch14.htm
字号:
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 parameterarray into a scalar variable. Then the scalar variable is usedto 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, Perlprovides 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 acceptedin new computer languages. I was first introduced to it whileworking with the scripting language for Microsoft Word. Ratherthan explain the technique in words, let me show you an examplein code, as shown in Listing 14.2. I think you'll understand thevalue of this technique very quickly.<P><IMG SRC="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 initializationworked.</I></BLOCKQUOTE><HR><BLOCKQUOTE><B>Listing 14.2 14LST02.PL-Setting Class PropertiesUsing 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 parameterto <TT>new()</TT>, but looks are deceivingin this case. The <TT>=></TT> operatordoes 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 arrayand 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 parametersby name using <TT>%params</TT>. Theinitialization 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 isbeing referred to. In addition, you can also use this techniqueto 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> propertywill remain undefined. You can use this technique with any typeof fuNCtion, not just constructors.<H3><A NAME="ExampleInheritaNCePerlStyle">Example: InheritaNCe, Perl Style</A></H3><P>You already know that inheritaNCe means that properties and methodsof a parent class will be available to child classes. This sectionshows you can use inheritaNCe in Perl.<P>First, a little diversion. You may not have realized it yet, buteach package can have its own set of variables that won't interferewith 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 Apackage B</PRE></BLOCKQUOTE><P>Notice that the <TT>::</TT> is beingused 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 inthis 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 namesof parent classes into a special array called <TT>@ISA</TT>.The elements of <TT>@ISA</TT> aresearched left to right for any missing methods. In addition, the<TT>UNIVERSAL</TT> class is invisiblytacked 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 linein the main package, it first looks in <TT>B</TT>.When the <TT>foo()</TT> fuNCtion isnot 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 baseclass <TT>B</TT> or the parent class<TT>A</TT>. Therefore, as a last-ditcheffort, Perl looks in the <TT>UNIVERSAL</TT>class. The <TT>bar()</TT> fuNCtionis not there, but a special fuNCtion called <TT>AUTOLOAD()</TT>is.<P>The <TT>AUTOLOAD()</TT> fuNCtion isnormally used to automatically load undefined fuNCtions. Its normaluse is a little beyond the scope of this book. However, in thisexample, I have changed it into an error reporting tool. Insteadof 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 undefinedand which class Perl was looking in. Notice that the message endswith a newline to prevent Perl from printing the script name andline number where the script death took place. In this case, theinformation would be meaningless because the line number wouldbe 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 causesless confusion when calling constructors from more than one parent.<P>This example also shows how to inherit the properties of a parentclass. By calling the parent class constructor fuNCtion, you caninitialize an anonymous hash that can be used by the base classfor adding additional properties.<P><IMG SRC="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>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>Call the constructor for the parent class, </I><TT><I>Inventory_item</I></TT><I>,and assign the resulting object refereNCe to </I><TT><I>$self</I></TT><I>.<BR>Create an entry in the anonymous hash for the </I><TT><I>INK_COLOR</I></TT><I>key.<BR>Bless the anonymous hash so that </I><TT><I>ref()</I></TT><I>will return </I><TT><I>Pen</I></TT><I>and return a refereNCe to the anonymous hash.<BR>Start the </I><TT><I>main</I></TT><I>namespace.<BR>Call the constructor for the </I><TT><I>Pen</I></TT><I>class. Assign the object refereNCe to </I><TT><I>$item</I></TT><I>.Note that an array with property-value pairs is passed to theconstructor.<BR>Print the three property values to verify that the property initializationworked.</I></BLOCKQUOTE><HR><BLOCKQUOTE><B>Listing 14.3 14LST03.PL-How to Call the Constructorof a Parent Class<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 Pen; @ISA = (Inventory_item); sub new { my($class) = shift; my(%params) = @_; my($self) = Inventory_item->new(@_); $self->{"INK_COLOR"} = $params{"INK_COLOR"}; return(bless($self, $class)); }package main; $pen = Pen->new( "PART_NUM" => "12A-34", "QTY_ON_HAND" => 34, "INK_COLOR" => "blue"); print("The part number is " . %{$pen}->{'PART_NUM'} . "\n");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -