diff options
author | Jacob Schatz <jschatz@gitlab.com> | 2016-11-17 22:48:46 +0300 |
---|---|---|
committer | Jacob Schatz <jschatz@gitlab.com> | 2016-11-17 22:48:46 +0300 |
commit | da57eb39cd2e5d8dd92b05d16f49681f1677f3e8 (patch) | |
tree | 0195e7b98b115d910676952a0c80398ca0bc16fc /doc/development/frontend.md | |
parent | 0b21a71aeb7383ea5584a25a2e4966ad266ff5fd (diff) | |
parent | 2159c8792b289bb27f9947fb834fbd497efeeb28 (diff) |
Merge branch 'google-singletons-are' into 'master'
Decide on and document a convention for singletons
> The singleton pattern is a design pattern that restricts the instantiation of a class to one object. This is useful when exactly one object is needed to coordinate actions across the system.
The simplest implementation uses an object literal to contain the logic.
```javascript
gl.MyThing = {
prop1: 'hello',
method1: () => {}
};
```
A live example of this is [GfmAutoComplete](https://gitlab.com/gitlab-org/gitlab-ce/blob/172aab108b875e8dc9a5f1d3c2d53018eff76ea1/app/assets/javascripts/gfm_auto_complete.js.es6)
Another approach makes use of ES6 `class` syntax.
```javascript
let singleton;
class MyThing {
constructor() {
if (!singleton) {
singleton = this;
singleton.init();
}
return singleton;
}
init() {
this.prop1 = 'hello';
}
method1() {}
}
gl.MyThing = MyThing;
```
A live example of this is [Sidebar](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/app/assets/javascripts/sidebar.js.es6)
Another functional approach to define Singleton using `Javascript Revealing Module Pattern` is like below
```javascript
/**
* 1. It instantiates only a single object
* 2. It is safe – it keeps the reference to the singleton inside a variable, which lives inside a lexical closure, so it is not accessible by the outside world
* 3. It allows privacy – you can define all private methods of your singleton inside the lexical closure of the first module pattern
* 4. No this keyword trap (no wrong context referring)
* 5. No use of new keyword
* 6. Easy to write test code
*/
//
const Singleton = (function () {
// Instance stores a reference to the Singleton
var instance;
function init() {
// Singleton
// Private methods and variables
function privateMethod(){
console.log( "I am private" );
}
var privateVariable = "Im also private";
var privateRandomNumber = Math.random();
return {
// Public methods and variables
publicMethod: function () {
console.log( "The public can see me!" );
},
publicProperty: "I am also public",
getRandomNumber: function() {
return privateRandomNumber;
}
};
};
return {
// Get the Singleton instance if one exists
// or create one if it doesn't
getInstance: function () {
if ( !instance ) {
instance = init();
}
return instance;
}
};
})();
const singletonObj = Singleton.getInstance()
```
## Are there points in the code the reviewer needs to double check?
## What does this MR do?
Creates a space for discussion and contribution for interested devs.
## Why was this MR needed?
## Screenshots (if relevant)
## Does this MR meet the acceptance criteria?
- [x] [Documentation created/updated](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/doc/development/doc_styleguide.md)
- [x] All builds are passing
(http://docs.gitlab.com/ce/development/merge_request_performance_guidelines.html)
- [x] Conform by the [style guides](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/CONTRIBUTING.md#style-guides)
- [x] [Squashed related commits together](https://git-scm.com/book/en/Git-Tools-Rewriting-History#Squashing-Commits)
## What are the relevant issue numbers?
See merge request !6620
Diffstat (limited to 'doc/development/frontend.md')
-rw-r--r-- | doc/development/frontend.md | 51 |
1 files changed, 51 insertions, 0 deletions
diff --git a/doc/development/frontend.md b/doc/development/frontend.md index ec8f2d6531c..9e782ab977f 100644 --- a/doc/development/frontend.md +++ b/doc/development/frontend.md @@ -205,6 +205,57 @@ command line. Please note: Not all of the frontend fixtures are generated. Some are still static files. These will not be touched by `rake teaspoon:fixtures`. +## Design Patterns + +### Singletons + +When exactly one object is needed for a given task, prefer to define it as a +`class` rather than as an object literal. Prefer also to explicitly restrict +instantiation, unless flexibility is important (e.g. for testing). + +``` +// bad + +gl.MyThing = { + prop1: 'hello', + method1: () => {} +}; + +// good + +class MyThing { + constructor() { + this.prop1 = 'hello'; + } + method1() {} +} + +gl.MyThing = new MyThing(); + +// best + +let singleton; + +class MyThing { + constructor() { + if (!singleton) { + singleton = this; + singleton.init(); + } + return singleton; + } + + init() { + this.prop1 = 'hello'; + } + + method1() {} +} + +gl.MyThing = MyThing; + +``` + ## Supported browsers For our currently-supported browsers, see our [requirements][requirements]. |