Last active
March 6, 2021 21:27
-
-
Save patrickkunka/a65a62928f5a9e2acca6d33277d728ce to your computer and use it in GitHub Desktop.
Factory Function Patterns
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Factory #1: Constructor Instantiation | |
* | |
* This example shows basic abstraction of constructor/class | |
* instantation. Additional error checking, validation of arguments | |
* could be added inside the factory, or just delegated to the constructor. | |
*/ | |
import Implementation from './Implementation'; | |
export default function factory() { | |
return new Implementation(...arguments); | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Factory #2: Instance Caching (Memoization) | |
* | |
* A pattern which is particularly useful for UI widgets, where | |
* we want to prevent the consumer from creating multiple | |
* instances on the same element. | |
*/ | |
import Implementation from './Implementation'; | |
/** | |
* @param {HTMLElement} input | |
* @param {object} [config={}] | |
* @return {Implementation} | |
*/ | |
function factory(input, config={}) { | |
let instance = null; | |
for (let i = 0; (instance = factory.cache[i]); i++;) { | |
// If instance found in cache with same `input` element, return that instance | |
// NB: In this example, the implementation exposes a public property holding | |
// a reference to its input element | |
if (instance.input === input) return instance; | |
} | |
// Else create new instance, add to cache and return it | |
instance = new Implementation(input, config); | |
factory.cache.push(instance); | |
return instance; | |
} | |
factory.cache = []; | |
export default factory; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Factory #3A: Dynamic Return Types | |
* | |
* An example where we might want to allow a factory function | |
* to return a different type depending on how we interact with | |
* it. | |
* | |
* The factory function accepts either a single element, or an | |
* array-like collection of elements. It then returns a single | |
* instance, or an array of instances as appropriate. | |
* | |
* While factories give us this flexibility, it should be | |
* avoided in favour of predictable API entry points. A refactored | |
* version using a seperate static method is shown afterwards (#3B). | |
*/ | |
import Implementation from './Implementation'; | |
/** | |
* @param {(HTMLElement|HTMLElement[])} inputs | |
* @param {object} [config={}] | |
* @return {(Implementation|Implementation[])} | |
*/ | |
export default function factory(inputs, config={}) { | |
if (Array.isArray(inputs) || typeof inputs.length === 'number') { | |
// Return many | |
return Array.from(inputs).map(input => new Implementation(input, config)); | |
} | |
// Return one | |
return new Implementation(inputs, config); | |
} | |
/** | |
* Factory #3B: Dynamic Return Types | |
* | |
* With this pattern, the most commonly used functionality | |
* is available via the most simple calling syntax, and more | |
* specialised functionality is seperated out into static | |
* methods. | |
*/ | |
import Implementation from './Implementation'; | |
/** | |
* @param {HTMLElement} input | |
* @param {object} [config={}] | |
* @return {Implementation} | |
*/ | |
function factory(input, config={}) { | |
return new Implementation(input, config); | |
} | |
/** | |
* @param {HTMLElement[]} inputs | |
* @param {object} [config={}] | |
* @return {Implementation[]} | |
*/ | |
factory.collection = (inputs, config={}) => { | |
return Array.from(inputs).map(input => new Implementation(input, config)); | |
} | |
export default factory; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Factory #4: Asynchronicity | |
* | |
* In this example, both constructor/class instantiation | |
* and asyncronous functionality is abstracted behind a single | |
* promise-returning factory. The promise resolves with | |
* an instance of the implementation. | |
*/ | |
import Implementation from './Implementation'; | |
/** | |
* @param {object} [config={}] | |
* @return {Promise<Implementation>} | |
*/ | |
export default function factory(config={}) { | |
const instance = new Implementation(config); | |
return instance.somethingAsync() | |
.then(() => instance); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment