Perl Cd Bookshelf [Electronic resources] نسخه متنی

اینجــــا یک کتابخانه دیجیتالی است

با بیش از 100000 منبع الکترونیکی رایگان به زبان فارسی ، عربی و انگلیسی

Perl Cd Bookshelf [Electronic resources] - نسخه متنی

| نمايش فراداده ، افزودن یک نقد و بررسی
افزودن به کتابخانه شخصی
ارسال به دوستان
جستجو در متن کتاب
بیشتر
تنظیمات قلم

فونت

اندازه قلم

+ - پیش فرض

حالت نمایش

روز نیمروز شب
جستجو در لغت نامه
بیشتر
لیست موضوعات
توضیحات
افزودن یادداشت جدید



13.3. Managing Instance Data


13.3.1. Problem


Each data attribute of an object,
sometimes named data members or properties, needs its own method for
access. How do you write functions that manipulate the object's
instance data?

13.3.2. Solution


Either write pairs of get and set methods that affect the appropriate
key in the object hash, like this:

sub get_name {
my $self = shift;
return $self->{NAME};
}
sub set_name {
my $self = shift;
$self->{NAME} = shift;
}

or make single methods that do both jobs depending on whether they're
passed an argument:

sub name {
my $self = shift;
if (@_) { $self->{NAME} = shift }
return $self->{NAME};
}

When setting a new value, sometimes it may be useful to return not
that new value, but the previous one:

# returns previously set value if changing it
sub age {
my $self = shift;
my $oldage = $self->{AGE};
if (@_) { $self->{AGE} = shift }
return $oldage;
}
$previous_age = $obj->age( $obj->age( ) + $TIME_PASSES );

13.3.3. Discussion


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:

$him = Person->new( );
$him->{NAME} = "Sylvester";
$him->{AGE} = 23;

then an argument could justifiably be made that they have violated
the interface and so deserve whatever they get.

For nominally private data elements, you may omit methods that access
them. However, then if—better make that when—you update
the implementation, you'll need to scour the class to find where
other methods within the class rely upon the particular
representation that you're now changing. To be squeaky clean, you
could have the class itself go through a mediated, functional
interface to access instance data.

This extraordinary care isn't strictly required by the class of its
own methods, but from the perspective of code that simply uses your
module, it most certainly is. By mandating a strictly functional
interface, you are free to alter your internal representation later
without fear of breaking user code. The functional interface allows
you to run arbitrary range checks and take care of any data
reformatting or conversion.

Here's a fancy version of the name method that
demonstrates this:

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} = $_;
}

If users, or even other classes through inheritance, had been
accessing the "NAME" 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.

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 invoke but folks outside the class cannot.

Here's an
example of creating a Person using the Alias module. When you update
these magical instance variables, you automatically update value
fields in the hash. Convenient, eh?

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);
our ($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;
}

You need to declare the package variables via our
because Alias plays with package globals by the same names as the
fields. To use globals while use
strict is in effect, you have to predeclare them.
These variables are localized to the block enclosing the
attr invocation, just as though
local were used on them. That means that they're
still considered global package variables with temporary values.

13.3.4. See Also


perltoot(1), perlboot(1),
perlobj(1), and perlbot(1);
the section on "Managing Instance Data" in Chapter 12 of
Programming Perl; the documentation for the
Alias module from CPAN;
Recipe 13.12



13.2. Destroying an Object13.4. Managing Class Data




Copyright © 2003 O'Reilly & Associates. All rights reserved.

/ 875