Stevan Little > Class-StrongSingleton-0.02 > Class::StrongSingleton

Download:
Class-StrongSingleton-0.02.tar.gz

Dependencies

Annotate this POD

View/Report Bugs
Module Version: 0.02   Source  

NAME ^

Class::StrongSingleton - A stronger and more secure Singleton base class.

SYNOPSIS ^

  package My::Singleton::Class;

  use base qw(Class::StrongSingleton);
  
  sub new {
     my ($class, %my_params) = @_;
         # create our object instance
         my $instance = { %my_params };
         bless($instance, $class);
         # and initialize it as a singleton
         $instance->_init_StrongSingleton();
         return $instance;
  }
  
  1;
  
  # later in your code ...
  
  # create the first instance of our class
  my $instance = My::Singleton::Class->new(param => "value");
  
  # try to create a 'new' one again, and
  # you end up with the same instance, not
  # a new one
  my $instance2 = My::Singleton::Class->new(param => "other value");

  # calling 'instance' returns the singleton
  # instance expected
  my $instance3 = My::Singleton::Class->instance();
  
  # although rarely needed, if you have to
  # you can destroy the singleton
  
  # either through the instance
  $instance->DESTROY();
  # or through the class
  My::Singleton::Class->DESTROY();
  
  # of course, this is assuming you 
  # did not override DESTORY yourself
  
  # Also calling 'instance' before calling 'new'
  # will returns a new singleton instance
  my $instance = My::Singleton::Class->instance();  

DESCRIPTION ^

This module is an alternative to Class::Singleton and Class::WeakSingleton, and provides a more secure Singleton class in that it takes steps to prevent the possibility of accidental creation of multiple instances and/or the overwriting of existsing Singleton instances. For a detailed comparison please see the "SEE ALSO" section.

Here is a description of how it all works. First, the user creates the first Singleton instance of the class in the normal way.

  my $obj = My::Singleton::Class->new("variable", "parameter");

This instance is then stored inside a lexically scoped variable within the Class::StrongSingleton package. This prevents the variable from being accessed by anything but methods from the Class::StrongSingleton package. At this point as well, the new method to the class is overridden so that it will always return the Singleton instance. This prevents any accidental overwriting of the Singleton instance. This means that any of the follow lines of code all produce the same instance:

  my $instance = $obj->instance();
  my $instance = My::Singleton::Class->instance();
  my $instance = $obj->new();
  my $instance = My::Singleton::Class->new();

Personally, I see this an an improvement over the usual Gang of Four style Singletons which discourages the use of the new method entirely. Through this method, a user can be able to use the Singleton class in a normal way, not having to know it's actually a Singleton. This can be handy if your design changes and you no longer need the class as a Singleton.

METHODS ^

_init_StrongSingleton

This method is used to initialize the Singleton instance, your class must call this. This is a protected method, meaning it can only be called by a subclass of Class::StrongSingleton, otherwise it will throw an exception. It also must be called as an instance method and not as a class method, which means that your constructor should look something like this:

  sub new {
        my $class = shift;
        my $instance = bless({}, $class);
        $instance->_init_StrongSingleton();
        return $instance;
  }

You also may not call _init_StrongSingleton once a Singleton instance has been established, if you do, and exception will be thrown. This is an unlikely error, but one that may come up if your class has complex initializers. In general you want the Class::StrongSingleton _init_StrongSingleton method to be the last step in your class initialization process. It should be noted, that this module performs just fine in multiple inheritance situations, just be sure the _init_StrongSingleton method gets properly called.

It is also important to note that there currently is a restriction on constructor names. Your class constructor must be named new, if it is not an exception is thrown in this method. This is because we hijack the constructor function to insure that no new instances are created, and need to be able to access it by name. In future versions (if there is request for it) I will put in functionality to be able to specify a specific constructor name.

NOTE: In version 0.01 this method was called _init, but since that is all too common a name, and could easily be accidentely overridden in a subclass, it has been changed. However to maintain backwards compatability, _init has been aliased to _init_StrongSingleton.

instance

If a Singleton instance already exists for the calling class, this will return that instance. Otherwise it will attempt to call new on the class, and pass any arguments it may have been given.

DESTROY

WARNING: As you may have already know, this functionality is a dangerous thing, and something not to be done lightly. Make sure you have a really good reason to do it, otherwise you might want to rethink your usage of Singletons.

That said, I felt it a good idea to include some means of destruction for these Singleton class instances. While more often than not you will want your Singleton to never go out of scope and therefore never need to be destroyed (except maybe during global destruction when the interpreter is exiting), there might be sometimes in a long running system/application that it would be desireable to have the ability to DESTROY (or refresh/reload) the Singleton instance of your class. So for these reasons i have also implemented a destructor for the class (using the built in DESTROY method).

This destructor will clean up/restore all of the changes made by the _init_StrongSingleton method, so that you class will be restored back to it's original state. Keep in mind, that perl will never call this DESTROY method itself, since there will always be a reference to the Singleton instance stored internally. So if you want to create a new instance you must call the DESTROY method yourself.

  my $instance1 = $obj->instance();
  $obj->DESTORY()
  my $instance2 = SingletonDerivedObject->new();

Now the Singleton instance stored in $instance1 is different than the Singleton instance in $instance2.

BUGS ^

None that I am aware of. Of course, if you find a bug, let me know, and I will be sure to fix it. This code is derived from code which has been in production use for over 2 years without incident.

CODE COVERAGE ^

I use Devel::Cover to test the code coverage of my tests, below is the Devel::Cover report on this module test suite.

 ------------------------ ------ ------ ------ ------ ------ ------ ------
 File                       stmt branch   cond    sub    pod   time  total
 ------------------------ ------ ------ ------ ------ ------ ------ ------
 Class/StrongSingleton.pm  100.0  100.0   66.7  100.0  100.0  100.0   97.1
 ------------------------ ------ ------ ------ ------ ------ ------ ------
 Total                     100.0  100.0   66.7  100.0  100.0  100.0   97.1
 ------------------------ ------ ------ ------ ------ ------ ------ ------

SEE ALSO ^

This module is an alternative to Class::Singleton and Class::WeakSingleton, and provides a more secure Singleton class in that it takes steps to prevent the possibility of accidental creation of multiple instances and/or the overwriting of existsing Singleton instances.

If you think this module is ridiculous overkill written by a paranoid freak, then by all means, use either Class::Singleton or Class::WeakSingleton, I will not be offended. However, if you think I may not be as crazy as people some think, then here is a list of what I see as valuable additions/changes that this module contributes to the world of perl Singletons.

The actual Singleton instance is not accessable to any other module.

Both Class::Singleton and Class::WeakSingleton store the Singleton instance in a package variable called _instance which is easily accessable from anywhere else in your code. I know this is just another case of "don't go there because you were not invited", personally I just don't like the idea that the Singleton is unprotected.

Class::StrongSingleton stores the Singleton instance in a lexically scoped package variable within the Class::StrongSingleton package itself, so short of some crazy low level pad-walking, you cannot get to it.

Classes can have 'normal' constructors.

The original Gang of Four Singleton pattern calls for the method instance to be used to call a private or protected constructor. I feel this restriction has more to do with the C++ language than it does with common sense. Both Class::Singleton and Class::WeakSingleton expect you to call instance, and to implement a private constructor called _new_instance, which the subclasser is expected to override.

Class::StrongSingleton takes a different approach, to initialize your Singleton, you must call _init_StrongSingleton as an instance method on a subclass of Class::StrongSingleton. An instance method is provided, but it is not the only constructor, but instead, just an accessor for the Singleton instance. Class::StrongSingleton allows you to use the standard constructor new to create your Singleton, and then hijacks the new method so that it will only ever return the Singleton instance.

All this may sound complicated (or maybe just stupid), but I do have my reasons. Singletons are a design "trick" to get around global variables, and sometimes can be overused/abused. On occasion, I have found myself refactoring out Singletons, to improve the design and/or efficiency of an application. Using the style of this module where new can be used quite normally, it makes it much easier to remove Singletons.

It is very difficult to create duplicate or errant instances of a Singleton.

With both Class::Singleton and Class::WeakSingleton a simple call to _new_instance will result in a non-Singleton instance of your Singleton class. Yes, yes, I know,... this is another case of "don't go there because you were not invited".

With Class::StrongSingleton; calling new will return the Singleton, calling instance will return the Singleton and directly calling _init_StrongSingleton will result in an exception. A class must purposfully create a constructor method which bypasses Class::StrongSingleton in order to create a duplicate or errant instance.

Once again, I am clearly a paranoid programmer, and you may be thinking 'Why doesn't this freak just use Java or something???'. But the fact is, I love programming in perl precisiely because I can do silly stuff like this. If you don't like/appreciate/care-for this style/methodology/illness then just don't use it, I really will not be offended at all :)

AUTHOR ^

stevan little, <stevan@iinteractive.com>

COPYRIGHT AND LICENSE ^

Copyright 2004 by Infinity Interactive, Inc.

http://www.iinteractive.com

This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself.

syntax highlighting: