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

📄 ch12_07.htm

📁 编程珍珠,里面很多好用的代码,大家可以参考学习呵呵,
💻 HTM
📖 第 1 页 / 共 3 页
字号:
<html><head><title>Managing Instance Data (Programming Perl)</title><!-- STYLESHEET --><link rel="stylesheet" type="text/css" href="../style/style1.css"><!-- METADATA --><!--Dublin Core Metadata--><meta name="DC.Creator" content=""><meta name="DC.Date" content=""><meta name="DC.Format" content="text/xml" scheme="MIME"><meta name="DC.Generator" content="XSLT stylesheet, xt by James Clark"><meta name="DC.Identifier" content=""><meta name="DC.Language" content="en-US"><meta name="DC.Publisher" content="O'Reilly &amp; Associates, Inc."><meta name="DC.Source" content="" scheme="ISBN"><meta name="DC.Subject.Keyword" content=""><meta name="DC.Title" content="Managing Instance Data"><meta name="DC.Type" content="Text.Monograph"></head><body><!-- START OF BODY --><!-- TOP BANNER --><img src="gifs/smbanner.gif" usemap="#banner-map" border="0" alt="Book Home"><map name="banner-map"><AREA SHAPE="RECT" COORDS="0,0,466,71" HREF="index.htm" ALT="Programming Perl"><AREA SHAPE="RECT" COORDS="467,0,514,18" HREF="jobjects/fsearch.htm" ALT="Search this book"></map><!-- TOP NAV BAR --><div class="navbar"><table width="515" border="0"><tr><td align="left" valign="top" width="172"><a href="ch12_06.htm"><img src="../gifs/txtpreva.gif" alt="Previous" border="0"></a></td><td align="center" valign="top" width="171"><a href="ch12_01.htm">Chapter 12: Objects</a></td><td align="right" valign="top" width="172"><a href="ch12_08.htm"><img src="../gifs/txtnexta.gif" alt="Next" border="0"></a></td></tr></table></div><hr width="515" align="left"><!-- SECTION BODY --><h2 class="sect1">12.7. Managing Instance Data</h2><p><a name="INDEX-2518"></a><a name="INDEX-2519"></a>Most classes create objects that are essentially just data structureswith several internal data fields (instance variables) plus methodsto manipulate them.</p><p><a name="INDEX-2520"></a><a name="INDEX-2521"></a>Perl classes inherit methods, not data, but as long as all accessto the object is through method calls anyway, this works out fine.If you want data inheritance, you have to effect it through methodinheritance.  By and large, this is not a necessity in Perl, becausemost classes store the attributes of their object in an anonymoushash.  The object's instance data is contained within this hash,which serves as its own little namespace to be carved up by whateverclasses do something with the object.  For example, if you want anobject called <tt class="literal">$city</tt> to have a data field named <tt class="literal">elevation</tt>, youcan simply access <tt class="literal">$city-&gt;{elevation}</tt>.  No declarations arenecessary.  But method wrappers have their uses.</p><p>Suppose you want to implement a <tt class="literal">Person</tt> object.  You decide to have adata field called "name", which by a strange coincidence you'll storeunder the key <tt class="literal">name</tt> in the anonymous hash that will serve as theobject.  But you don't want users touching the data directly.  To reapthe rewards of encapsulation, users need methods to access thatinstance variable without lifting the veil of abstraction.</p><p><a name="INDEX-2522"></a>For example, you might make a pair of accessor methods:<blockquote><pre class="programlisting">sub get_name {    my $self = shift;    return $self-&gt;{name};}sub set_name {    my $self      = shift;    $self-&gt;{name} = shift;}</pre></blockquote>which leads to code like this:<blockquote><pre class="programlisting">$him = Person-&gt;new();$him-&gt;set_name("Frodo");$him-&gt;set_name( ucfirst($him-&gt;get_name) );</pre></blockquote>You could even combine both methods into one:<blockquote><pre class="programlisting">sub name {    my $self = shift;    if (@_) { $self-&gt;{name} = shift }    return $self-&gt;{name};}</pre></blockquote>This would then lead to code like this:<blockquote><pre class="programlisting">$him = Person-&gt;new();$him-&gt;name("Frodo");$him-&gt;name( ucfirst($him-&gt;name) );</pre></blockquote><a name="INDEX-2523"></a>The advantage of writing a separate function for each instancevariable (which for our <tt class="literal">Person</tt> class might be name, age, height,and so on) is that it is direct, obvious, and flexible.  The drawbackis that every time you want a new class, you end up defining one ortwo nearly identical methods per instance variable.  This isn't toobad for the first few, and you're certainly welcome to do it that wayif you'd like.  But when convenience is preferred over flexibility,you might prefer one of the techniques described in the following sections.</p><p>Note that we will be varying the implementation, not the interface.  Ifusers of your class respect the encapsulation, you'll be able totransparently swap one implementation for another without the usersnoticing.  (Family members in your inheritance tree using your classfor a subclass or superclass might not be so forgiving, since they knowyou far better than strangers do.)  If your users have been peeking andpoking into the private affairs of your class, the inevitable disasteris their own fault and none of your concern.  All you can do is live upto your end of the contract by maintaining the interface.  Trying tostop everyone else in the world from ever doing something slightlywicked will take up all your time and energy--and in the end, failanyway.</p><p><a name="INDEX-2524"></a><a name="INDEX-2525"></a><a name="INDEX-2526"></a>Dealing with family members is more challenging.  If a subclassoverrides a superclass's attribute accessor, should it access the samefield in the hash, or not?  An argument can be made either way,depending on the nature of the attribute.  For the sake of safety inthe general case, each accessor can prefix the name of the hash fieldwith its own classname, so that subclass and superclass can both havetheir own version.  Several of the examples below, including thestandard <tt class="literal">Struct::Class</tt> module, use this subclass-safe strategy.You'll see accessors resembling this:<blockquote><pre class="programlisting">sub name {    my $self = shift;    my $field = __PACKAGE__ . "::name";    if (@_) { $self-&gt;{$field} = shift }    return $self-&gt;{$field};}</pre></blockquote>In each of the following examples, we create a simple<tt class="literal">Person</tt> class with fields <tt class="literal">name</tt>,<tt class="literal">race</tt>, and <tt class="literal">aliases</tt>, each with anidentical interface but a completely different implementation.  We'renot going to tell you which one we like the best, because we like themall the best, depending on the occasion.  And tastes differ.  Somefolks prefer stewed conies; others prefer fissssh.</p><h3 class="sect2">12.7.1. Field Declarations with use fields</h3><a name="INDEX-2527"></a><a name="INDEX-2528"></a><a name="INDEX-2529"></a><a name="INDEX-2530"></a><a name="INDEX-2531"></a><p>Objects don't have to be implemented as anonymous hashes.  Anyreference will do.  For example, if you used an anonymous array,you could set up a constructor like this:<blockquote><pre class="programlisting">sub new {    my $invocant = shift;    my $class = ref($invocant) || $invocant;    return bless [], $class;}</pre></blockquote>and have accessors like these:<blockquote><pre class="programlisting">sub name {    my $self = shift;    if (@_) { $self-&gt;[0] = shift }    return $self-&gt;[0];}sub race {    my $self = shift;    if (@_) { $self-&gt;[1] = shift }    return $self-&gt;[1];}sub aliases {    my $self = shift;    if (@_) { $self-&gt;[2] = shift }    return $self-&gt;[2];}</pre></blockquote><a name="INDEX-2532"></a>Arrays are somewhat faster to access than hashes and don't takeup quite as much memory, but they're not at all convenient touse.  You have to keep track of the index numbers (not just inyour class, but in your superclass, too), which must somehow indicatewhich pieces of the array your class is using.  Otherwise, you might reusea slot.</p><p>The <tt class="literal">use fields</tt> pragma addresses all of these points:<blockquote><pre class="programlisting">package Person;use fields qw(name race aliases);</pre></blockquote><a name="INDEX-2533"></a><a name="INDEX-2534"></a><a name="INDEX-2535"></a><a name="INDEX-2536"></a>This pragma does not create accessor methods for you, but it does relyon some built-in magic (called <em class="emphasis">pseudohashes</em>) todo something similar.  (You may wish to wrap accessors around thefields anyway, as we do in the following example.) Pseudohashes arearray references that you can use like hashes because they have anassociated key map table.  The <tt class="literal">use fields</tt> pragmasets this key map up for you, effectively declaring which fields arevalid for the <tt class="literal">Person</tt> object; this makes the Perlcompiler aware of them.  If you declare the type of your objectvariable (as in <tt class="literal">my Person $self</tt>, in the nextexample), the compiler is smart enough to optimize access to thefields into straight array accesses.  Perhaps more importantly, itvalidates field names for type safety (well, typo safety, really) atcompile time.  (See the section <a href="ch08_03.htm#ch08-sect-pseudo">Section 12.3.5, "Pseudohashes"</a> in <a href="ch08_01.htm">Chapter 8, "References"</a>.)</p><p>A constructor and sample accessors would look like this:<blockquote><pre class="programlisting">package Person;use fields qw(name race aliases);sub new {    my $type = shift;    my Person $self = fields::new(ref $type || $type);    $self-&gt;{name} = "unnamed";    $self-&gt;{race}  = "unknown";    $self-&gt;{aliases} = [];    return $self;}sub name {    my Person $self = shift;    $self-&gt;{name} = shift if @_;    return $self-&gt;{name};}sub race {    my Person $self = shift;    $self-&gt;{race} = shift if @_;    return $self-&gt;{race};}sub aliases {    my Person $self = shift;    $self-&gt;{aliases} = shift if @_;    return $self-&gt;{aliases};}1;</pre></blockquote>If you misspell one of the literal keys used to access the pseudohash,

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -