JavaScript/Notes/PrivateProxy: Difference between revisions
| Line 11: | Line 11: | ||
'''Example:''' User wants to be able to interact with "program" objects on a calendar. The <dfn>program</dfn> can be then modified by the user. | '''Example:''' User wants to be able to interact with "program" objects on a calendar. The <dfn>program</dfn> can be then modified by the user. | ||
The application handles modification of program objects through a <dfn>ProgramProxy</dfn>, by calling <dfn>setPhases</dfn>, <dfn>setCampaigns</dfn>. The | The application handles modification of program objects through a <dfn>ProgramProxy</dfn>, by calling <dfn>setPhases</dfn>, <dfn>setCampaigns</dfn>. The client of the API may call <dfn>buildHTML</dfn> to generate new HTML for the program or <dfn>toJSON</dfn> 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. While commonly used, these prefabricated solutions entail a much larger codebase with less specifics to your particular situation. | |||
<source lang="javascript"> | <source lang="javascript"> | ||
Revision as of 14:49, 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. While commonly used, these prefabricated solutions entail a much larger codebase with less specifics to 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.