JavaScript/Notes/PrivateProxy: Difference between revisions

From Noisebridge
Jump to navigation Jump to search
Garrett (talk | contribs)
Garrett (talk | contribs)
Line 14: Line 14:


=== Alternatives ===  
=== Alternatives ===  
The popular alternative to this approach is MVC with libraries such as Backbone or YUI app framework. While commonly used, these prefabricated solutions entail a much larger codebase with less specifics to your particular situation.  
The popular alternative to this approach is MVC with libraries such as Backbone or YUI app framework. Prefabricated solutions often entail a much larger codebase with less specificity to the design of your particular situation.  
   
   
<source lang="javascript">
<source lang="javascript">

Revision as of 14:54, 17 May 2014

Proxy

A proxy is as an interface to something else.

Private Proxy

The private proxy exposes a public interface object. This public interface object delegates some of its responsibility to a private instance.

Structural Pattern: The private and public instances are tightly coupled. They can share data with each other within the function where they are defined, but not outside of there.

Usage: This pattern is useful when you have details and complexities that can be hidden. By exposing a very limited set of methods, the code allows caller less opportunity to modify and break the objects it produces.

Example: User wants to be able to interact with "program" objects on a calendar. The program can be then modified by the user.

The application handles modification of program objects through a ProgramProxy, by calling setPhases, setCampaigns. The client of the API may call buildHTML to generate new HTML for the program or toJSON to get a JSON representation of it.

Alternatives

The popular alternative to this approach is MVC with libraries such as Backbone or YUI app framework. Prefabricated solutions often entail a much larger codebase with less specificity to the design of your particular situation.

<source lang="javascript"> var Program = function(A) {

 "use strict";
 var phaseListClassName = "program-phase-list",
     phaseClassName = "program-phase";
 function Program(id, config) {
   var start = config.startDate,
       end = config.endDate;
   this.id = id;
   this.dateRange = new A.DateRange(start, end);
   this.phases = config.phases.slice();
 }
 var programs = {},
     programProxies = {};
 var phaseListElement = document.createElement("ul"),
     phaseElement = document.createElement("li");
 phaseListElement.className = phaseListClassName;
 phaseElement.className = phaseClassName;
 function ProgramProxy(id, config) {
   this.id = id;
   this.start = config.startDate;
   this.displayName = config.name;
   this.end = config.endDate;
   programs[id] = new Program(id, config);
 }
 ProgramProxy.prototype = {
   setPhases: function(phases) {
     if(phases && phases.slice) {
       programs[this.id].phases = phases.slice();
     }
   },
   buildHTML: function() {
     var program = programs[this.id],
         html = "";
     html += buildPhaseHTML(program);
     html += buildCampaignHTML(program);
     return html;
   }
 };
 var div = document.createElement("div");
 function buildPhaseHTML(program) {
   div.innerHTML = "";
   var i, li,
       phases = program.phases,
       len = phases.length,
       phaseRationalValue,
       ul = phaseListElement.cloneNode(false);
   ul.id = "program-" + program.id;
   for(i = 0; i < len; i++) {
     li = phaseElement.cloneNode(false);
     li.id = "program-"
           + program.id 
           + "-phase-"
           + phases[i].name  
           + "";
     li.style.width = 
       getPhaseWidth(phases[i], program.dateRange.duration);
     ul.appendChild(li);
   }
   div.appendChild(ul);
   return div.innerHTML;
 }

 function buildCampaignHTML() {
   return"";

"

    " + "
  • fixme:\u00A0buildCampaignHTML" + "

";

 }
 function getPhaseWidth(phase, programDuration) {
   var phaseDateRange = new A.DateRange(
     phase.startDate, phase.endDate);
   var rationalValue = phaseDateRange.duration/programDuration;
   return (0|100 * rationalValue) + "%";
 }
 function getOrCreateProgram(config) {
   return programProxies[config.id] || 
     (programProxies[config.id] = new ProgramProxy(config.id, config));
 }
 function removeProgram(id) {
   if(!programs[id]) {
     throw new ReferenceError("Program: " 
       + id
       + " does not exist." );
   }
   delete programs[id];
   delete programProxies[id];
 }
 return {
   getOrCreate: getOrCreateProgram,
   remove: removeProgram
 };

}({

 DateRange: DateRange // defined elsewhere.

}); </source>

`Program.getOrCreate` returns a `ProgramProxy`.

`ProgramProxy` has two methods, both of which delegate to `Program` instances.

The body of buildHTML <source lang="javascript"> setPhases: function(phases) {

if(phases && phases.slice) {
   programs[id].phases = phases.slice();
 }

} </source>

This is possible because `ProgramProxy` and each `Program` have the same id. Each are stored in one of two objects, keyed by their id. See also: Proxy Design Pattern.