I have a class class defined to keep track of some dynamic data that will be updated during runtime. I want the instance of this class to be accessible by all routes I have defined in my application:
export default class Manager {
constructor() {
let self = this;
self.table = [];
}
addEntity(obj){
let self = this;
self.table.push(obj);
}
}
Let's say I run my app and some event happens. I then invoke manager.addEntity(...some_event...);
.
self.table
will then have a new element. I want to be able to have a route access this information by requesting the route's url, maybe GET /api/table/
. Unfortunately I currently have no way of accessing the instance of the class.
Should I assign the reference to the instance of the class to a global variable? This is an anti-pattern and I'd like to avoid doing this if possible.
My server is defined using normal remended code:
import http from 'http';
import { env, mongo, port, ip, apiRoot } from './config';
import api from './api';
import express from './services/express';
import mongoose from './services/mongoose';
import Manager from './lib/manager.js';
const app = express(apiRoot, api);
const server = http.createServer(app);
mongoose.connect(mongo.uri, { useMongoClient: true });
mongoose.Promise = Promise;
new Manager().initialize(server);
setImmediate(() => {
server.listen(port, ip, () => {
console.log(
'Express server listening on http://%s:%d, in %s mode',
ip,
port,
env,
);
});
});
export default app;
I have a class class defined to keep track of some dynamic data that will be updated during runtime. I want the instance of this class to be accessible by all routes I have defined in my application:
export default class Manager {
constructor() {
let self = this;
self.table = [];
}
addEntity(obj){
let self = this;
self.table.push(obj);
}
}
Let's say I run my app and some event happens. I then invoke manager.addEntity(...some_event...);
.
self.table
will then have a new element. I want to be able to have a route access this information by requesting the route's url, maybe GET /api/table/
. Unfortunately I currently have no way of accessing the instance of the class.
Should I assign the reference to the instance of the class to a global variable? This is an anti-pattern and I'd like to avoid doing this if possible.
My server is defined using normal remended code:
import http from 'http';
import { env, mongo, port, ip, apiRoot } from './config';
import api from './api';
import express from './services/express';
import mongoose from './services/mongoose';
import Manager from './lib/manager.js';
const app = express(apiRoot, api);
const server = http.createServer(app);
mongoose.connect(mongo.uri, { useMongoClient: true });
mongoose.Promise = Promise;
new Manager().initialize(server);
setImmediate(() => {
server.listen(port, ip, () => {
console.log(
'Express server listening on http://%s:%d, in %s mode',
ip,
port,
env,
);
});
});
export default app;
Share
Improve this question
asked Jan 24, 2018 at 19:41
PGTPGT
2,0392 gold badges27 silver badges49 bronze badges
1
- Sounds like you are indeed looking for a global variable. There's only one instance of your class for your whole application? – Bergi Commented Jan 24, 2018 at 21:09
2 Answers
Reset to default 3Edit: Refer to the ment by Bergi below as to why the answer I posted is a bad idea.
--
Export a instance of that class that all the routes import. Instead maybe something like this (single instance pattern):
class Manager {
...
}
export default new Manager();
Whether singleton class is justified or not is decided on per case basis.
It can be justified if the use of a class can provide certain benefits:
a class may be instantiated multiple times, while there should exist default instance
a class may be extended
a class can provide syntactic or functional benefits (for instance, drastic performance optimization for prototype chain in Node.js/V8)
If there's a chance that it has to be instantiated multiple times (nested applications, testing, etc.), it can be a class with default instance. This is naturally provided by JS modules, including ES modules:
export class Manager {
constructor() {
this.table = [];
}
addEntity(obj) {
this.table.push(obj);
}
}
export default new Manager();
Notice that Manager
is exported in case there's a need to instantiate or extend it.
If this is not the case, then KISS principle can be applied, and plain object can be used instead:"
export default {
table: [],
addEntity(obj) {
this.table.push(obj);
}
};
KISS principle can be applied further; if pushing an object to the array is all that the class does, addEntity
isn't very helpful. It can be omitted, so we end up with a single array.
In Express.js, application-wide variables are conventionally stored as application settings, so the variable (either the entire object or table array) could be stored and retrieved from application instance:
app.set('managed entities', []);
...
app.get('managed entities').push(...);
The requirement is to have access to application instance, so the code that uses managed entities
setting should reside inside middleware function. On the other hand, this provides more flexibility. The setting can be overridden if needed.