Observer Pattern 2nd Look: Wildcard Syntax, Multiple Objects to Observe and the Power of an Extend() Utility Function
//Main App Module var sApp = sApp || {}; sApp = (function(){ //Our main sub modules. var CALC = CALC || {}, GlobalObserver = GlobalObserver || {}, anotherCalc = anotherCalc || {}; //Utility function for creating a hierarchy of namespaces //On the fly. function extend( ns, ns_string ) { var parts = ns_string.split('.'), parent = ns, pl, i; if (parts[0] == "CALC") { parts = parts.slice(1); } pl = parts.length; for (i = 0; i < pl; i++) { //create a property if it doesnt exist if (typeof parent[parts[i]] == 'undefined') { parent[parts[i]] = {}; } parent = parent[parts[i]]; } return parent; } //Our Main Observer Class //This guy sees everything. GlobalObserver = function() { var Observable = function() { this.subscribers = []; }; Observable.prototype.subscribe = function(callback) { this.subscribers.push(callback); }; Observable.prototype.unsubscribe = function(callback) { var i = 0, len = this.subscribers.length; for (i; i < len; i+=1) { if (this.subscribers[i] === callback) { this.subscribers.splice(i, 1); return; } } }; Observable.prototype.publish = function(n, z) { var i = 0, len = this.subscribers.length; for (i; i < len; i+=1) { this.subscribers[i](n, z); } }; return { Observable : Observable }; }; //Extends Any Class with the specified parameters. function extendAPI(namespace, publicAPIName , arrOperations){ var nme = namespace.name + '.' + publicAPIName; extend(namespace, nme); var operations = arrOperations; var conc = []; for(var k = 0; k < arrOperations.length; k++){ conc.push(nme + '.' + arrOperations[k]); extend(namespace, conc[k]); } }; //Constructor for our simple math. CALC = (function(){ return { name: 'CALC' }; }()); //Initialize the namespace we'll need. extendAPI(CALC, 'simpleMath', ['add', 'subtract', 'multiply', 'divide']); //Our public functions. CALC.simpleMath = { add: function(n1, n2){ console.log(n1 + n2); return n1 + n2; }, subtract: function(n1, n2){ console.log(n1 - n2); return n1 - n2; }, multiply: function(n1, n2){ console.log(n1 * n2); return n1 * n2; }, divide: function(n1, n2){ console.log(n1 / n2); return n1 / n2; } }; //The constructor for our slightly more complicated math. exSum = (function(){ return { name: 'anotherCalc' }; }()); extendAPI(exSum, 'notSoSimpleMath', ['exponent', 'summation']); exSum.notSoSimpleMath = { exponent: function(num1, num2){ console.log(Math.pow(num1, num2)); return Math.pow(num1, num2); }, summation: function(F, L){ var lSquared = exSum.notSoSimpleMath.exponent(L,2), fSquared = exSum.notSoSimpleMath.exponent(F,2), g = lSquared - fSquared, h = CALC.simpleMath.add(g,F), z = CALC.simpleMath.add(h, L), summ = CALC.simpleMath.divide(z, 2); console.log(summ); return summ; } }; //Here, we publish to an observable function //Which does the calculations and prints it them //Out in the console. function executeAPI(namespace, publicFunctions, observable){ //access and execute our public API via wildcard syntax //observe the entire public API subscribeAll(namespace, publicFunctions, observable); //let's test out our functions console.log(observable); console.log("Test 1."); observable.publish(1, 10); console.log("Test 2."); observable.publish(123, 130); }; //Subscribe to all functions within a namespace. function subscribeAll(namespace, publicFunctions, observable){ var arr, x; for(x in publicFunctions){ //wildcard syntax arr = x.match(/(.*)/); if (arr != null) { observable.subscribe(publicFunctions[arr[0]]); } } }; //Unsubscribe to all functions within a namespace. function unsubscribeAll(namespace, publicFunctions, observable){ var arr2, y; for(y in publicFunctions){ //wildcard syntax arr2 = y.match(/(.*)/); if (arr2 != null) { observable.unsubscribe(publicFunctions[arr2[0]]); } } }; //Global Observer Initialization and execution of public APIs var GLOBAL_OBSERVER = new GlobalObserver(); var bigBrother = new GLOBAL_OBSERVER.Observable(); executeAPI(CALC, CALC.simpleMath, bigBrother); executeAPI(anotherCalc, exSum.notSoSimpleMath, bigBrother); //Unsubscribe when we're done. unsubscribeAll(CALC, CALC.simpleMath, bigBrother); unsubscribeAll(anotherCalc, CALC.simpleMath, bigBrother); //public functions available to anyone outside the app, //just for fun return{ extendClass : extend, executeAPI: executeAPI, add: CALC.simpleMath.add, subtract: CALC.simpleMath.subtract, multiply: CALC.simpleMath.multiply, divide: CALC.simpleMath.divide, exponenent: exSum.notSoSimpleMath.exponent, summation: exSum.notSoSimpleMath.summation } }());











