I wanted to step up my JS game, and move on from mostly closure based scripting, so I decided to write an application in node. I don't have much experience with prototype based programming, and I guess it's a little too early for ES6 (well, maybe with traceur).
During planning of my app I saw that often I'll need container behaviour. So, I know I could implement it with a class, but I thought: why not use trait-like thingy instead?
Gamemode.js, concrete class
'use strict';
var Script = require('../Script');
var Gamemode = module.exports = function () {
Script.apply(this, arguments);
};
Gamemode.prototype = Object.create(Script.prototype);
Gamemode.prototype.constructor = Gamemode;
Script.js, abstract class
'use strict';
var helper = require("./helper");
var _ = require("lodash");
var Script = module.exports = function () {
if (this.constructor === Script) {
throw new Error("Can't initialize abstract class!");
}
var defaultDefinitions = {
MAX_PLAYERS: '(500)'
};
_.merge(this, helper.collection("definition", defaultDefinitions));
};
Script.prototype.build = function () {
return this.definitions;
};
helper.js
'use strict';
var _ = require("lodash");
var capitalize = function (string) {
return string.charAt(0).toUpperCase() + string.slice(1).toLowerCase();
};
var container = function (singular, mutable) {
if (undefined === mutable) {
mutable = false;
}
var accessors = {},
methodSingular = capitalize(singular),
plural = singular + 's',
methodPlural = capitalize(plural);
accessors['get' + methodPlural] = function () {
return this[plural];
};
accessors['set' + methodPlural] = function (value) {
if (undefined === value) {
delete this[plural];
}
this[plural] = value;
return this;
};
if (mutable) {
accessors['add' + methodSingular] = function (item) {
_.assign(this[plural], item);
};
accessors['remove' + methodSingular] = function (item) {
delete this[plural][item];
};
}
return accessors;
};
var collection = function (name, defaults) {
if (undefined === defaults) {
defaults = {};
};
var all = {};
all[name + 's'] = _.defaults({}, defaults);
return _.merge(all, container(name, true));
};
var helper = module.exports = {
capitalize: capitalize,
container: container,
collection: collection
};
It works properly, now every instance of Gamemode
has its own "definitions" property, with getDefinitions
, setDefinitions
, addDefinition
and removeDefinition
methods.
- Am I violating any rules, like encapsulation?
- Am I adding property somewhere else than in the constructor?
- Would creating a "container" object instead be better?