JavaScript/Notes/PrivateProxy: Difference between revisions

From Noisebridge
Jump to navigation Jump to search
No edit summary
Line 126: Line 126:
</source>
</source>


`Program.getOrCreate` returns a `ProgramProxy`.
<code>Program.getOrCreate</code> returns a <code>ProgramProxy</code>.


`ProgramProxy` has two methods, both of which delegate to `Program` instances.  
<code>ProgramProxy</code> has two methods, both of which delegate to <code>Program</code> instances.  


The body of buildHTML
The body of buildHTML:
<source lang="javascript">
<source lang="javascript">
setPhases: function(phases) {
setPhases: function(phases) {
Line 139: Line 139:
</source>
</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: [http://sourcemaking.com/design_patterns/proxy Proxy Design Pattern].
Because <code>ProgramProxy</code> and each <code>Program</code> have the same id, any <code>Program</code> or <code>ProgramProxy</code> instance counterpart can access its corresponding counterpart from within any of its instance methods.
 
This is implemented by both <code>Program</code> and <code>ProgramProxy</code> instances being stored in a corresponding object for, keyed by id.  
 
See also: [http://sourcemaking.com/design_patterns/proxy Proxy Design Pattern].

Revision as of 19:12, 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 share data with each other only within the scope where they are defined.

Usage: Details and complexities of the underlying object must be hidden. By exposing a very limited set of methods, the public interface offers little opportunity to modify and break the objects it produces, while protecting the integrity of the underlying, corresponding private objects.

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>

Because ProgramProxy and each Program have the same id, any Program or ProgramProxy instance counterpart can access its corresponding counterpart from within any of its instance methods.

This is implemented by both Program and ProgramProxy instances being stored in a corresponding object for, keyed by id.

See also: Proxy Design Pattern.