Editing
JavaScript/Notes/Factory
(section)
Jump to navigation
Jump to search
Warning:
You are not logged in. Your IP address will be publicly visible if you make any edits. If you
log in
or
create an account
, your edits will be attributed to your username, along with other benefits.
Anti-spam check. Do
not
fill this in!
== Step 1: getById == <source lang=javascript> function ElementWrapper(id, x) { this.id = id; this.x = x; } ElementWrapper.instances = {}; ElementWrapper.getById = function(id, x) { if(ElementWrapper.instances.hasOwnProperty(id)) return ElementWrapper.instances[id]; return ElementWrapper.instances[id] = new ElementWrapper(id, x); }; </source> ==== Problems ==== '''Problem:''' Not DRY. Cannot be arbitrarily reused other constructor functions. '''Problem:''' <code>ArgumentList</code> ([http://www.ecma-international.org/ecma-262/5.1/#sec-11.2 §11.2]) is set to two. '''Problem:''' Encapsulation. The factory and the constructor are exposed publicly.</p> === Decorator Factory Aspect === <p>A <dfn>Decorator Factory Aspect</dfn> is a <dfn>Factory method</dfn>, added as an <dfn>Aspect</dfn> to a constructor of a <dfn>Decorator</dfn>.</p> <p>Before we add a <dfn>Factory</dfn> to a constructor function for an element <dfn>decorator</dfn>, Let's define <dfn>Decorator</dfn> (also called a <dfn>wrapper</dfn>), <dfn>Factory</dfn> and <dfn>Aspect</dfn>. </p> ; Decorator Pattern : Add functionality to an object by wrapping it. ([http://en.wikipedia.org/wiki/Decorator_pattern Wikipedia link]) ; Factory Pattern : The Factory pattern is a creational design pattern that encapsulates the processes of creating objects ([http://en.wikipedia.org/wiki/Factory_pattern Wikipedia link]). That way, we can create objects lazily and pool them in an object pool. ; Aspect : <cite>introduces separation of concern(s), as modularization of functionality</cite> ([http://en.wikipedia.org/wiki/Aspect-oriented_programming Wikipedia link]) === Decorator Examples === <p> <dfn>Decorator</dfn> is very common in JavaScript. For example: [http://developer.yahoo.com/yui/docs/Element.js.html YAHOO.util.Element] <dfn>decorates</dfn> an element, jQuery <dfn>decorates</dfn> a collection of elements. </p> === Factory Example === <p>The <dfn>Factory</dfn> gets or creates a <dfn>decorated</dfn> element. The <code>id</code> of the <dfn>wrapper</dfn> is the same as the <code>id</code> of the element. This is the part I want to make reusable:</p> <source lang="javascript">/** * @constructor * @param {String} id - the id of the element and widget. */ function ElementWrapper(id, x) { this.id = id; this.x = x; } // Factory. // TODO: How can I make this generic/reusable? ElementWrapper.instances = {}; ElementWrapper.getById = function(id, x) { if(this.instances.hasOwnProperty(id)) return this.instances[id]; return this.instances[id] = new this(id, x); }; ElementWrapper.prototype = { show : function() { document.getElementById(this.id).style.visibility = "visible"; } }; </source> ==== Benefits ==== <p> Solves the problem of creating only one decorator per element <code>id</code>. </p> <p> By calling <code>getElementById</code>, the <dfn>decorator</dfn> can avoid some of the problems with changing node references with <code>innerHTML</code> (though state changes must still be managed manually). </p> === Problem: <abbr title="Dont Repeat Yourself">DRY</abbr> === <blockquote> <p>Don't Repeat Yourself</p> <p> Every piece of knowledge must have a single, unambiguous, authoritative representation within a system. </p> </blockquote> <p> It is cumbersome and error-prone to write out a <dfn>Factory</dfn> each time. Since this is an idiom I use a lot, it makes sense to make it reusable.</p> <p> I want to have a generic <code>getById</code> method that can be reused and will return an instance of the constructor that it is called on. I want to be able to pass extra arguments to that constructor (varargs). </p> === Problem: Publicly Exposed Constructor === A factory should not expose the constructor, but should hide it so that the factory method must be used. I will explain the solution to this problem in part II. === Encapsulate the Parts That Vary === <strong>What varies?</strong> The <code>id</code> parameter variable of <code>getById</code> does not change; it will always be present in any generic <dfn>Factory</dfn>. The parts of the <dfn>Factory</dfn> that vary are: The additional zero or more arguments (varargs, this case, <code>x</code>), and the context, or <dfn>thisArg</dfn>. Resolving the context arg is easy. If I can solve passing varargs to a constructor in a generic context, it will be possible to create a generic <dfn>Factory</dfn> <dfn>Aspect</dfn>. ==== Function newApply ==== A way to call <code>new</code> with variable arguments would solve this problem. A <code>new + apply()</code> would provide the varargs functionality of <code>apply</code>, but passed to <code><nowiki>[[Construct]]</nowiki></code>, not <code><nowiki>[[Call]]</nowiki></code>. (see [http://www.ecma-international.org/ecma-262/5.1/#sec-15.3.4.3 Function.prototype.apply], [http://www.ecma-international.org/ecma-262/5.1/#sec-13.2.1 <code><nowiki>[[Call]]</nowiki></code>]). The source code for <code>newApply</code>: <source lang="javascript"> /** * @param {Function} fun constructor to be invoked. * @param {Array} args arguments to pass to the constructor. * Instantiates a constructor and uses apply(). */ function F(){}; function newApply(fun, args) { var i; F.prototype = fun.prototype; // Add prototype. F.prototype.constructor = fun; i = new F; fun.apply(i, args); // Apply the original constructor. return i; } </source> <h4>Usage</h4> Early versions of this method appeared in APE JavaScript library, which has been copied. ==== What's newApply Good For? ==== Generic <code>getById</code> function I wanted, to use <dfn>aspect</dfn> with any constructor function. ===== Library Aspect ===== <source lang="javascript"> function getById(id) { if(!this.hasOwnProperty("instances")) this.instances = {}; return this.instances[id] || (this.instances[id] = newApply(this, arguments)); } </source> ===== Implementation ===== <source lang="javascript"> function ElementWrapper(id, x, y) { this.id = id; this.x = x; this.y = y; } ElementWrapper.getById = getById; </source> ===== Usage ===== <source lang="javascript"> ElementWrapper.getById("a", 2, 3).y; // 3 </source> Example in jsbin: [http://jsbin.com/AgARAXI/1/embed?html,js,output live example]. ==== Using the Generic <code>getById</code> ==== <p>This <code>getById</code> method used with <code>ElementWrapper</code> (above) or any other constructor that acts as a <dfn>Decorator</dfn> to an element and accepts the element's <code>id</code> as its first argument. All other arguments will be passed to the constructor using <code>newApply</code>. </p> <source lang="javascript">Slider = function(id, dir) { /* ... */ }; // Factory. Slider.getById = getById; </source> <p> Then I can use: </p> <source lang="javascript">Slider.getById( "weight", 1 ); </source> <p> Subsequent calls to:</p> <source lang="javascript">Slider.getById( "weight" ); </source> <p>β will return the same <code>Slider</code> instance.</p> === More Examples === <p>I have used a modified version of this approach for many widgets, including * [http://garretts.github.io/ape-javascript-library/example/widget/calendar/ Calendar], * [http://garretts.github.io/ape-javascript-library/example/drag/Slider/ Slider] * [http://garretts.github.io/ape-javascript-library/example/widget/scroller/ Scroller] Autocomplete (can't run off Github pages because there is no server side processing). This pattern is useful for building widgets that can be initialized lazily, on a bubbled event.</p> (slider uses [https://noisebridge.net/wiki/JavaScript/Notes/Function#Function.prototype.call overflow hidden]). === Reusable Concept === <p>Another closely related technique is <i>Decorator</i> that accepts an <em>element</em> instead of an element's <code>id</code>. This is covered by <code>getByNode</code>. </p> <p> In most patterns, encapsulating the parts that vary entails creating an class. However, in JavaScript, this Factory pattern was simple to implement by using just two functions (<code>getById</code>) and leveraging the dynamic nature of JavaScript. </p> === Links === <p> [http://www.artima.com/intv/dry.html Orthogonality and the DRY Principle], A Conversation with Andy Hunt and Dave Thomas, Part II by Bill Venners March 10, 2003 </p>
Summary:
Please note that all contributions to Noisebridge are considered to be released under the Creative Commons Attribution-NonCommercial-ShareAlike (see
Noisebridge:Copyrights
for details). If you do not want your writing to be edited mercilessly and redistributed at will, then do not submit it here.
You are also promising us that you wrote this yourself, or copied it from a public domain or similar free resource.
Do not submit copyrighted work without permission!
To protect the wiki against automated edit spam, we kindly ask you to solve the following CAPTCHA:
Cancel
Editing help
(opens in new window)
Navigation menu
Personal tools
Not logged in
Talk
Contributions
Log in
Request account
Namespaces
Page
Discussion
English
Views
Read
Edit
View history
More
Search
Dig in!
Noisebridge
- Status: MOVED
- Donate
- ABOUT
- Accessibility
- Vision
- Blog
Manual
MANUAL
Visitors
Participation
Community Standards
Channels
Operations
Events
EVENTS
Guilds
GUILDS
- Meta
- Electronics
- Fabrication
- Games
- Music
- Library
- Neuro
- Philosophy
- Funding
- Art
- Crypto
- Documentation/Wiki
Wiki
Recent Changes
Random Page
Help
Categories
(Edit)
Tools
What links here
Related changes
Special pages
Page information