Thursday, December 20, 2012

Occamsrazor.js 2.0 API ehnancement

I released version 2.0 of occamsrazor.js. My goal is to further simplify the API. This example is taken from my last post:

//mediator

var pubsub = occamsrazor();

// from now a validator is a simple function
var is_archive = function (obj){
    return 'getNumbers' in obj;
};

// the archive object

var archive = (function (){
    var numbers = [];
    return {
        getNumbers: function (){
            return numbers;
        },
        addItem: function (number){
            numbers.push(number);
            // this notify the event to the mediator
            pubsub.publish('changed', this);
        }
    };
}());

// the printsum isn't changed

var printsum = (function (){
    return {
        print: function (n){
            console.log(n);
        },
        sum_and_print: function (archive){
            var i,sum = 0;
            for(i = 0;i < archive.length; i++){
                sum += archive[i];
            }
            this.print(sum);
        }
    };
}());

// subscribe the event
// subscribe is an alias of "add" and "on"

// the list of validators now is before the function
pubsub.subscribe(["changed",is_archive], function (evt, archive){
    printsum.sum_and_print(archive.getNumbers());
});

//you can use a single string instead of a function as a validator

Thursday, December 6, 2012

Mediator pattern with occamsrazor.js

The mediator design pattern can be very useful to decouple a group of objects. Let's see how.

Let's say we have two very simple objects. The first is an archive of numbers:

var archive = (function (){
    var numbers = [];
    return {
        getNumbers: function (){
            return archive;
        },
        addItem: function (number){
            archive.push(number);
        }
    };
}());

The second object prints the sum of the numbers of the previous object:

var printsum = (function (){
    return {
        print: function (n){
            console.log(n);
        },
        sum_and_print: function (archive){
            var i,sum = 0;
            for(i = 0;i < archive.length; i++){
                sum += archive[i];
            }
            this.print(n)
        }
    };
}());

Ok. Now we need to recalculate and print the sum each time a new item is added to the archive. The first solution is straightforward:

...

        addItem: function (number){
            archive.push(number);
            // we call directly the function
            printsum.sum_and_print(archive);
        }
...

This could be a solution but It has a drawback: we bind explicity the two objects together. With many objects and direct dependencies this could be very difficult to manage. Moreover, chaging or adding other dependencies could translate in changing extensively the (already tested) code.

The mediator

The mediator is an object that mediates between other objects. Instead of calling functions directly we notify events to the mediator. The mediator calls every function that is subscribed to a certain event.
Let's rewrite the example using occamsrazor.js to build a mediator:

//mediator

var pubsub = occamsrazor();

// we need 2 validators, one for the event and the second for the object

// this validate the type of the event

var is_changed_event = occamsrazor.validator(function (evt){
    return evt === 'changed';
});


// this validate the type of the object

var is_archive = occamsrazor.validator(function (obj){
    return 'getNumbers' in obj;
});


// the archive object

var archive = (function (){
    var numbers = [];
    return {
        getNumbers: function (){
            return numbers;
        },
        addItem: function (number){
            numbers.push(number);
            // this notify the event to the mediator
            pubsub.publish('changed', this);
        }
    };
}());

// the printsum isn't changed

var printsum = (function (){
    return {
        print: function (n){
            console.log(n);
        },
        sum_and_print: function (archive){
            var i,sum = 0;
            for(i = 0;i < archive.length; i++){
                sum += archive[i];
            }
            this.print(sum);
        }
    };
}());

// subscribe the event

pubsub.subscribe(function (evt, archive){
    printsum.sum_and_print(archive.getNumbers());
}, [is_changed_event,is_archive])

Build a mediator with occamsrazor.js has another advantage: events are notified only for the objects that pass every validator.

Next challenge: try to integrate occamsrazor.js with backbone.js 
Stay tuned !