Category: | Miscellaneous |
Author/Contact Info | dkubb |
Description: | Class::Flyweight is a module allows you to simply use the flyweight pattern in your modules. The major advantage to using this pattern is that the object data is not stored inside the blessed object itself. There is no way for a user of your module to access data in your object, unless you have provided the interface. I am submitting this module for a code review, as I'm close to uploading it to CPAN. Before that I'd to get the monks' feedback and opinions before I take it to the next step. In particular I am not sure of the following:
|
package Class::Flyweight;
=head1 NAME
Class::Flyweight - implement the flyweight pattern in OO perl
=head1 SYNOPSIS
package MyPackage;
use strict;
use Class::Flyweight;
#Create the flyweight object store
my $flyweight = Class::Flyweight->new;
#make a new flyweight object
sub new {
my $class = shift;
my $self = $flyweight->clone({}, $class);
return $self;
}
#fetch the data structure from the object
#store, then access it directly.
sub get_name {
my $self = shift;
my $data = $flyweight->fetch($self);
return $data->{name};
}
#this is required to ensure proper clean-up
sub DESTROY {
my $self = shift;
$flyweight->delete($self);
}
1;
=head1 ABSTRACT
This module provides a lightweight
framework for developing perl modules
that have private internal data
structures. It should be impossible
to modify an object's data stucture in
ways not intended you, the author, thus
providing true encapsulation of object
data.
=head1 DESCRIPTION
=head2 What is the flyweight pattern?
The flyweight pattern is a little known
technique for implementing objects. The
main difference between the flyweight
pattern and a normal object, is that the
blessed object is very small, and does not
carry around the object information. Rather
it acts like an "index" and knows how to get
at the object data, but can only do so from
within the lexical scope that we define the
Class::Flyweight object in.
The key is that the object data storage is
done inside the scope that the class and
it's methods are defined in. Only the class
author can access the data, and provide
interfaces for others to do the same. It
*should* be impossible to get at this data
any other way, thus providing true object
encapsulation.
The concept was first introduced to me in
Damian Conway's amazing book, Object Oriented
Perl2. Class::Flyweight is based on his examples
on page 302, and encapsulating the functionality
he illustrates, hiding the details of accessing
the object store from you.
=head2 How do I use it?
To begin using the flyweight pattern, you must
create a new flyweight object, using the c<new>
constructor. Make sure that this is done inside
the perl module you are writing.
Next, make sure that all your methods pull
the object data from the data store using the
C<fetch> method. It will return a valid reference
to the data inside the object. Please make sure
that you do not allow direct access to modify the
object data from your methods. Otherwise, that
defeats the purpose of Class::Flyweight, and it
would be better and simpler at that point to use
pure arrays/hashes/etc.
One final thing you need to remember is to
make a DESTROY method for your class. It
will be responsible for calling the C<delete>
method to ensure clean-up of the object data
when the object goes out of scope.
Normally perl's garbage collection will clean
out an object once the number of variables
referencing it has dropped to 0. In this
system, the object and the object's data are
not tied directly. Perl's garbage collection
facility has no way of knowing it needs to
clean the data out unless you tell it to
explicitly though using the C<delete> method.
The Synopsis contains a package that shows
a complete working example.
=cut
use strict;
use Carp;
use vars qw($VERSION);
$VERSION = '0.01';
#Internal Method. Ensure that any objects created
#with this class are cleaned up properly.
sub DESTROY {
my $self = shift;
#by the time DESTROY is called, we must
#not have any objects left.
croak 'usage: must do $flyweight->delete($self) in $self->DESTROY'
if %$self;
}
=head1 METHODS
=over 4
=item * C<new>
my $flyweight = Class::Flyweight->new;
The C<new> contructor is responsible
for creating a new flyweight object.
=cut
sub new {
my $class = shift;
return bless {}, $class;
}
=item * C<clone>
my $new_object = $flyweight->clone($reference);
my $new_object = $flyweight->clone($reference, $class);
The C<clone> method will create a new object
blessed into $class, that allows you to access
the data in the $flyweight data store.
The second argument is a reference to a perl data
type. Any perl reference can be used.
=cut
sub clone {
@_ >= 2 or croak 'usage: $flyweight->clone(OBJECT,[CLASS])';
my $self = shift;
my $index;
$index = rand
until $index and not exists $self->{$index};
$self->{$index} = shift;
return bless \$index, shift || scalar caller;
}
=item * C<fetch>
my $data_ref = $flyweight->fetch($self);
The C<fetch> method returns a reference to
the object data inside the object store.
The reference can be any valid reference,
and is not limited to hashes or arrays. Any
object reference can be retrieved from the
object store.
=cut
sub fetch {
@_ == 2 or croak 'usage: $flyweight->fetch(OBJECT)';
my $self = shift;
my $index = shift;
return $self->{$$index};
}
=item * C<delete>
$flyweight->delete($self);
The C<delete> method is responsible for cleaning
out the $self object from the data store, once
it has gone out of scope.
It must be called, before destruction, either by
the class author, or ideally in the classes
DESTROY method.
=cut
sub delete {
@_ == 2 or croak 'usage: $flyweight->delete(OBJECT)';
my $self = shift;
my $index = shift;
#decrement the reference count, so the object
#data is cleaned up properly
delete $self->{$$index};
}
=item * C<each>
while(my $object = $flyweight->each) {
#... do something with/to each object ...
}
The C<each> Class method will iterate and
return each object in the flyweight object
store.
=cut
sub each {
wantarray and croak 'usage: each() only returns 1 argument';
my $self = shift;
my $next_key = each %$self;
return bless \$next_key, scalar caller
if defined $next_key;
}
=pod
=back
=head1 BUGS
None that I know of. Please let me know if you
find anything, or have any suggestions.
=head1 AUTHOR
Dan Kubb <dkubb@cpan.org>. Vancouver, BC, Canada.
Intitial revision July 7, 2001.
=head1 ACKNOWLEDGEMENTS
=over 4
=item *
A special thanks goes out to Damian Conway for his
excellent book, Object Oriented Perl, which first
introduced me to the flyweight concept, among many
others.
=item *
The folks at perlmonks.org for providing and
contributing to a forum where I have learned more
about perl than at any other time since I first
typed #!/usr/bin/perl.
=back
=head1 COPYRIGHT
Class::Flyweight is free software; you can redistribute
it and/or modify it under the terms of the "Perl
Artistic License".
=head1 SEE ALSO
=head2 Object Encapsulation Made Easy
See the following essay by Damian Conway, that
explains how flyweight objects work, and provides
several other alternatives to providing object
encapsulation.
http://www.csse.monash.edu.au/~damian/TPC/1999/Encapsulation/Paper
+.html
=cut
1;
|
|
---|
Replies are listed 'Best First'. | |
---|---|
Re (tilly) 1: Class::Flyweight - implement the flyweight pattern in OO perl
by tilly (Archbishop) on Jul 09, 2001 at 07:27 UTC | |
Re: Class::Flyweight - implement the flyweight pattern in OO perl
by simonm (Vicar) on Jul 09, 2001 at 02:30 UTC | |
Re: Class::Flyweight - implement the flyweight pattern in OO perl
by Anonymous Monk on Jul 09, 2001 at 22:58 UTC |
Back to
Code Catacombs