I have been building some pretty large apps lately and I found the need for the registry design pattern in some of my javascript. I went with this approach because I wanted to minimize the power my objects had, yet I needed some kind of blackboard where all objects could check and report to.
In addition I found that implementing events onto the class made for a very effective event handler as well.
var Registry = new Class({ Implements : [Events], conf : {}, set : function(path,value){ var fragments = path.split('/'); if( fragments.shift() !== '') return false; // remove empty, first component if(fragments.length > 0 && fragments[fragments.length - 1] == '') fragments.pop(); var obj = {}; var ref = obj; var len = fragments.length; if( len > 0){ for(i = 0; i < len-1; i++){ ref[fragments[i]] = {}; ref = ref[fragments[i]]; } ref[fragments[len-1]] = value; this.conf = $merge(this.conf,obj); } else { this.conf = value; } }, get : function(path){ var fragments = path.split('/'); if( fragments.shift() !== '') return null; if(fragments.length > 0 && fragments[fragments.length -1] == '') fragments.pop(); var ref = this.conf; var path_exists = true; var i = 0; var len = fragments.length; while(path_exists && i < len){ path_exists = path_exists && (ref[fragments[i]] !== undefined); ref = ref[fragments[i]]; i++; } return ref; } });
The class is pretty simple but it provides for a powerful hierarchical syntax. Only two methods are supplied ‘get’ and ’set’.
Example:
var reg = new Registry(); reg.set('/Options/Default',{'name' : 'test', 'version' : 1}); reg.set('/Options/Default/name', 'changed'); reg.set('/dynamically/creates/nested/objects', true); reg.get('/Options/Default'); /* returns { name : 'changed', version : 1 } */ reg.get('/Options/Default/version'); // returns 1 reg.get('/'); /* returns { Options : { Default : { name : 'changed', version : 1 } }, dynamically : { creates : { nested : { objects : true } } } } */
I found it extremely useful for configuration objects for classes that were initialized in a tree fashion. It also seemed to help with the readability and organization of code. I also had several places where I had multiple objects doing completely different things to the same Request.JSON result. With this class I just stored it in a single place and fired off my event. I found it extremely useful to use the class as a global event manager for cases such as this. I ended up using a dot notation naming convention for my events which helped greatly in documentation and API design.
reg.addEvent('App.initialize',function(){}); reg.addEvent('App.shutdown',function(){}); reg.addEvent('Data.feed1.loaded',function(){}); reg.fireEvent('App.shutdown');
In my actual production code I had my Registry class implement my Singleton Class Mutator. This way I could initialize the registry object multiple times in my code without the need to worry about scope.
December 4th, 2008 at 1:00 pm
Nice work Nathan. I have a small bit of this functionality in my Hash extensions (http://www.clientcide.com/docs/Native/Hash.Extras#Hash:getFromPath) that allows you to get a value from a path, but having a two way interface is very slick. Keep it up!
December 4th, 2008 at 1:05 pm
[...] White has posted over on his blog a nice bit of work. He’s released a registry class for MooTools that lets you do stuff like [...]
December 9th, 2008 at 9:38 am
Why not just use JSON?
In your examples:
reg.addEvent(’App.initialize’,function(){});
can be:
App.initialize = function(){}
December 9th, 2008 at 10:03 am
@someone:
There is nothing that prevents one from using JSON Requests to load the registry object.
I would not recommend using the syntax in your example. ‘App.initialize’ is just a generic event. I was trying to demonstrate a global event handler. In this case when the Application as a whole is initialized. Any other code that needs to fire can listen to this event.
June 21st, 2009 at 1:26 pm
Hi Nathan. I evolved your registry to meet my needs, also I fixed several issues, see specs.
http://gist.github.com/133613