mailRe: The singleton design pattern for the old 'self.relax.data' data structure.


Others Months | Index by Date | Thread Index
>>   [Date Prev] [Date Next] [Thread Prev] [Thread Next]

Header


Content

Posted by Edward d'Auvergne on March 08, 2007 - 04:04:
On 3/7/07, Chris MacRaild <c.a.macraild@xxxxxxxxxxx> wrote:
On Wed, 2007-03-07 at 19:06 +1100, Edward d'Auvergne wrote:

> Hi,
>
> After careful thought about design patterns, I've decided to try to
> use the singleton pattern for the old 'self.relax.data' data
> structure.  See http://en.wikipedia.org/wiki/Singleton_pattern for
> more information about this design pattern.  I'll try to use the
> second simple example under the heading 'Python Borg pattern'.  The
> benefit of this pattern is that each module can use the code:
>
> from data import Data
> relax_data = Data()
>
> As Data will be a singleton if two modules used by relax instantiate
> the Data class then the global 'relax_data' in both modules will be
> the same instance.  Therefore if a method from the
> 'special_fns.model_free' module modifies the data structure, all the
> other relax modules using the singleton will see the changes.  The
> benefit of this pattern is that the data structure is similar in
> concept to a global variable but only modules utilising it will have
> it in one of their namespaces.  Also 'self.relax.data' will not need
> to be passed around inside the program, simplifying the code.  What do
> you think of the idea?

One issue here, identified on the wikipedia page, is that __init__() is
called for each call of Singleton(). Therefore all of the standard
__init__() stuff - inialising variables and empty containers - will
happen every time the Singleton instance is sought. This is clearly not
what we want. Ofcourse there are many ways around that by cleverly
hiding the initialisation stuff, but its starting to look like a complex
solution to what should be a simple problem.

I am aware of the execution of __init__() but this won't be an issue in the final construction of the relax data storage object. The object will be multilayered. The first layer, equivalent to the current top level Data class, will be a dictionary type and it's __init__() method will be empty. There may be a few variables (current_run, etc.) and methods defined inside this object but these will be in the scope of the class rather than the __init__() method.

The second layer will be data containers identified by the keys of the
top level dictionary type object.  This layer's __init__() method will
not be called each time.  The current Data.__init__() method will be
shifted to this layer (actually I'll probably rename Data to
RunContainer and then create a new Data object).  I'm still unsure but
I think I'll try to leave all __init__() functions empty and define
initial variables and objects in the scope of the class, eg:

class RunContainer:
   # The molecule-residue-spin object.
   mol = MoleculeList()

   # The diffusion tensor object.
   diff = DiffContainer()

   # Molecular structure.
   structure = StructureContainer()

   def __init__():
       pass


The third layer will be data containers for specific data types. For example the diffusion tensor data structure, the Scientific PDB data structures (and future molecular structure data structures), and the molecule-residue-spin multi-object structure (each of these three layers will consist of two objects - a list type object whereby each element is a specific data storage object).


Something like:

class Data:
    ...
Data = Data()

in the data module, then everywhere else:

from data import Data as relax_data


By rebinding the name 'Data' with an instance of the class, we effectively prevent accidental creation of additional instances, and the import makes that instance availible wherever we need it.

I do think that the relax data storage object is the absolute ideal situation for the implementation of the Singleton design pattern. There is only one instance of this object ever and all parts of relax should worship it - relax is designed around this object. It is the pillar that props up all of the program. And the relax saved stated is a copy of this object.

The Singleton construction is also very powerful for relax scripts.
It allows the script access to the data storage object without needing
to pass the object to the script.  Importantly it also allows the unit
test framework access to the structure without invoking relax itself.
And it is also very easy to implement cleanly - just have a look at
the current 1.3 line code base.  The relax data storage object is now
implemented as a Singleton and almost all of the relax test suite
passes.  The only failure is in one functional test whereby a saved
program state is loaded - this is because the state.load() user
function is not working yet.

Cheers,

Edward



Related Messages


Powered by MHonArc, Updated Thu Mar 08 11:20:29 2007