📄 ch13_04.htm
字号:
<HTML><HEAD><TITLE>Recipe 13.3. Managing Instance Data (Perl Cookbook)</TITLE><METANAME="DC.title"CONTENT="Perl Cookbook"><METANAME="DC.creator"CONTENT="Tom Christiansen & Nathan Torkington"><METANAME="DC.publisher"CONTENT="O'Reilly & Associates, Inc."><METANAME="DC.date"CONTENT="1999-07-02T01:42:17Z"><METANAME="DC.type"CONTENT="Text.Monograph"><METANAME="DC.format"CONTENT="text/html"SCHEME="MIME"><METANAME="DC.source"CONTENT="1-56592-243-3"SCHEME="ISBN"><METANAME="DC.language"CONTENT="en-US"><METANAME="generator"CONTENT="Jade 1.1/O'Reilly DocBook 3.0 to HTML 4.0"><LINKREV="made"HREF="mailto:online-books@oreilly.com"TITLE="Online Books Comments"><LINKREL="up"HREF="ch13_01.htm"TITLE="13. Classes, Objects, and Ties"><LINKREL="prev"HREF="ch13_03.htm"TITLE="13.2. Destroying an Object"><LINKREL="next"HREF="ch13_05.htm"TITLE="13.4. Managing Class Data"></HEAD><BODYBGCOLOR="#FFFFFF"><img alt="Book Home" border="0" src="gifs/smbanner.gif" usemap="#banner-map" /><map name="banner-map"><area shape="rect" coords="1,-2,616,66" href="index.htm" alt="Perl Cookbook"><area shape="rect" coords="629,-11,726,25" href="jobjects/fsearch.htm" alt="Search this book" /></map><div class="navbar"><p><TABLEWIDTH="684"BORDER="0"CELLSPACING="0"CELLPADDING="0"><TR><TDALIGN="LEFT"VALIGN="TOP"WIDTH="228"><ACLASS="sect1"HREF="ch13_03.htm"TITLE="13.2. Destroying an Object"><IMGSRC="../gifs/txtpreva.gif"ALT="Previous: 13.2. Destroying an Object"BORDER="0"></A></TD><TDALIGN="CENTER"VALIGN="TOP"WIDTH="228"><B><FONTFACE="ARIEL,HELVETICA,HELV,SANSERIF"SIZE="-1"><ACLASS="chapter"REL="up"HREF="ch13_01.htm"TITLE="13. Classes, Objects, and Ties"></A></FONT></B></TD><TDALIGN="RIGHT"VALIGN="TOP"WIDTH="228"><ACLASS="sect1"HREF="ch13_05.htm"TITLE="13.4. Managing Class Data"><IMGSRC="../gifs/txtnexta.gif"ALT="Next: 13.4. Managing Class Data"BORDER="0"></A></TD></TR></TABLE></DIV><DIVCLASS="sect1"><H2CLASS="sect1"><ACLASS="title"NAME="ch13-14105">13.3. Managing Instance Data</A></H2><DIVCLASS="sect2"><H3CLASS="sect2"><ACLASS="title"NAME="ch13-pgfId-465">Problem<ACLASS="indexterm"NAME="ch13-idx-1000004495-0"></A><ACLASS="indexterm"NAME="ch13-idx-1000004495-1"></A><ACLASS="indexterm"NAME="ch13-idx-1000004495-2"></A><ACLASS="indexterm"NAME="ch13-idx-1000004495-3"></A></A></H3><PCLASS="para">Each data attribute of an object, sometimes called data members or properties, needs its own method for access. How do you write these functions to manipulate the object's instance data?</P></DIV><DIVCLASS="sect2"><H3CLASS="sect2"><ACLASS="title"NAME="ch13-pgfId-471">Solution</A></H3><PCLASS="para">Either write pairs of get and set methods that affect the appropriate key in the object hash, like this:</P><PRECLASS="programlisting">sub get_name { my $self = shift; return $self->{NAME};} sub set_name { my $self = shift; $self->{NAME} = shift;} </PRE><PCLASS="para">Or, make single methods that do both jobs depending on whether they're passed an argument:</P><PRECLASS="programlisting">sub name { my $self = shift; if (@_) { $self->{NAME} = shift } return $self->{NAME};} </PRE><PCLASS="para">Sometimes, it's useful to return the previous value when setting a new value:</P><PRECLASS="programlisting">sub age { my $self = shift; my $prev = $self->{AGE}; if (@_) { $self->{AGE} = shift } return $prev;} # sample call of get and set: happy birthday!$obj->age( 1 + $obj->age );</PRE></DIV><DIVCLASS="sect2"><H3CLASS="sect2"><ACLASS="title"NAME="ch13-pgfId-521">Discussion</A></H3><PCLASS="para"><ACLASS="indexterm"NAME="ch13-idx-1000004509-0"></A>Methods are how you implement the public interface to the object. A proper class doesn't encourage anyone to poke around inside its innards. Each data attribute should have a method to update it, retrieve it, or both. If a user writes code like this:</P><PRECLASS="programlisting">$him = Person-><CODECLASS="literal">new()</CODE>;$him->{NAME} = "Sylvester";$him->{AGE} = 23;</PRE><PCLASS="para">then they have violated the interface, so deserve whatever they get.</P><PCLASS="para">For nominally private data elements, you may omit methods that access them.</P><PCLASS="para">By mandating a strictly functional interface, you are free to alter your internal representation later without fear of breaking code. The functional interface allows you to run arbitrary range checks and take care of any data reformatting or conversion.</P><PCLASS="para">Here's a fancy version of the <CODECLASS="literal">name</CODE> method that demonstrates this:</P><PRECLASS="programlisting">use Carp;sub name { my $self = shift; return $self->{NAME} unless @_; local $_ = shift; croak "too many arguments" if @_; if ($^W) { /[^\s\w'-]/ && carp "funny characters in name"; /\d/ && carp "numbers in name"; /\S+(\s+\S+)+/ || carp "prefer multiword name"; /\S/ || carp "name is blank"; } s/(\w+)/\u\L$1/g; # enforce capitalization $self->{NAME} = $_;} </PRE><PCLASS="para">If users, even other classes through inheritance, had been accessing the <CODECLASS="literal">"NAME"</CODE> field directly, you couldn't add this kind of code later. By insisting on only indirect, functional access to all data attributes, you keep your options open.</P><PCLASS="para">If you're used to C++ objects, then you're accustomed to being able to get at an object's data members as simple variables from within a method. The Alias module from CPAN provides for this, as well as a good bit more, such as the possibility of private methods that the object can call but folks outside the class cannot.</P><PCLASS="para">Here's an example of creating a Person using the <ACLASS="indexterm"NAME="ch13-idx-1000006816-0"></A>Alias module. When you update these magical instance variables, you automatically update value fields in the hash. Convenient, eh?<ACLASS="indexterm"NAME="ch13-idx-1000004985-0"></A><ACLASS="indexterm"NAME="ch13-idx-1000004985-1"></A><ACLASS="indexterm"NAME="ch13-idx-1000004985-2"></A><ACLASS="indexterm"NAME="ch13-idx-1000004985-3"></A></P><PRECLASS="programlisting">package Person;# this is the same as before...sub new { my $that = shift; my $class = ref($that) || $that; my $self = { NAME => undef, AGE => undef, PEERS => [], }; bless($self, $class); return $self;}use Alias qw(attr);use vars qw($NAME $AGE @PEERS);sub name { my $self = attr shift; if (@_) { $NAME = shift; } return $NAME;};sub age { my $self = attr shift; if (@_) { $AGE = shift; } return $AGE;}sub peers { my $self = attr shift; if (@_) { @PEERS = @_; } return @PEERS;}sub exclaim { my $self = attr shift; return sprintf "Hi, I'm %s, age %d, working with %s", $NAME, $AGE, join(", ", @PEERS);}sub happy_birthday { my $self = attr shift; return ++$AGE;}</PRE><PCLASS="para">You need <CODECLASS="literal">use</CODE> <CODECLASS="literal">vars</CODE> because Alias plays with package globals by the same names as the fields. To use globals while <CODECLASS="literal">use</CODE> <CODECLASS="literal">strict</CODE> is in effect, you have to predeclare them. These variables are localized to the block enclosing the <CODECLASS="literal">attr( )</CODE> call, just as though <CODECLASS="literal">local</CODE> were used on them. That means that they're still considered global package variables with temporary values.</P></DIV><DIVCLASS="sect2"><H3CLASS="sect2"><ACLASS="title"NAME="ch13-pgfId-573">See Also</A></H3><PCLASS="para"><ICLASS="filename">perltoot </I>(1), <ICLASS="filename">perlobj </I>(1), and <ICLASS="filename">perlbot </I>(1); <ACLASS="olink"HREF="../prog/ch05_01.htm">Chapter 5</A> of <ACLASS="citetitle"HREF="../prog/index.htm"TITLE="Programming Perl"><CITECLASS="citetitle">Programming Perl</CITE></A>; the documentation for the Alias module from CPAN; <ACLASS="xref"HREF="ch13_12.htm"TITLE="Generating Attribute Methods Using AUTOLOAD">Recipe 13.11</A>; <ACLASS="xref"HREF="ch13_13.htm"TITLE="Solving the Data Inheritance Problem">Recipe 13.12</A></P></DIV></DIV><DIVCLASS="htmlnav"><P></P><HRALIGN="LEFT"WIDTH="684"TITLE="footer"><TABLEWIDTH="684"BORDER="0"CELLSPACING="0"CELLPADDING="0"><TR><TDALIGN="LEFT"VALIGN="TOP"WIDTH="228"><ACLASS="sect1"HREF="ch13_03.htm"TITLE="13.2. Destroying an Object"><IMGSRC="../gifs/txtpreva.gif"ALT="Previous: 13.2. Destroying an Object"BORDER="0"></A></TD><TDALIGN="CENTER"VALIGN="TOP"WIDTH="228"><ACLASS="book"HREF="index.htm"TITLE="Perl Cookbook"><IMGSRC="../gifs/txthome.gif"ALT="Perl Cookbook"BORDER="0"></A></TD><TDALIGN="RIGHT"VALIGN="TOP"WIDTH="228"><ACLASS="sect1"HREF="ch13_05.htm"TITLE="13.4. Managing Class Data"><IMGSRC="../gifs/txtnexta.gif"ALT="Next: 13.4. Managing Class Data"BORDER="0"></A></TD></TR><TR><TDALIGN="LEFT"VALIGN="TOP"WIDTH="228">13.2. Destroying an Object</TD><TDALIGN="CENTER"VALIGN="TOP"WIDTH="228"><ACLASS="index"HREF="index/index.htm"TITLE="Book Index"><IMGSRC="../gifs/index.gif"ALT="Book Index"BORDER="0"></A></TD><TDALIGN="RIGHT"VALIGN="TOP"WIDTH="228">13.4. Managing Class Data</TD></TR></TABLE><HRALIGN="LEFT"WIDTH="684"TITLE="footer"><FONTSIZE="-1"></DIV<!-- LIBRARY NAV BAR --> <img src="../gifs/smnavbar.gif" usemap="#library-map" border="0" alt="Library Navigation Links"><p> <a href="copyrght.htm">Copyright © 2002</a> O'Reilly & Associates. All rights reserved.</font> </p> <map name="library-map"> <area shape="rect" coords="1,0,85,94" href="../index.htm"><area shape="rect" coords="86,1,178,103" href="../lwp/index.htm"><area shape="rect" coords="180,0,265,103" href="../lperl/index.htm"><area shape="rect" coords="267,0,353,105" href="../perlnut/index.htm"><area shape="rect" coords="354,1,446,115" href="../prog/index.htm"><area shape="rect" coords="448,0,526,132" href="../tk/index.htm"><area shape="rect" coords="528,1,615,119" href="../cookbook/index.htm"><area shape="rect" coords="617,0,690,135" href="../pxml/index.htm"></map> </BODY></HTML>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -