The builders of the pyramids were killed and buried within the pyramid as an early form of architectural design encapsulation.
So shall it be with Javascript.
Problem: your program has 30 classes in an unstructured mess.
Solution: gather related classes into sealed "Pyramids", forcing strict structure upon your unruly code.
Here I present the Pyramid model, each Javascript Class is surrounded by stone, and the occupants are forced to communicate by radio. Stone is an
anonymous closure, radio is a
pubsub. When a constructor is called, its last act is to delete its own scope.
- Organises your classes into privately scoped groups "Pyramids"
- Nothing outside a Pyramid may access anything inside the Pyramid, the Pyramids are loosely coupled.
- Each Pyramid publishes selected methods so that other Pyramids may subscribe to them.
- One line of code per class, and one line per Pyramid.
Here we have an "Pyramid Object" that represents the
constructors for a group of classes.
models = {Model: null, Scenario: null, Turret: null, Targets: null, GunRange: null},
Each null is replaced with the real class constructor when it is declared.
controllers = {Clicks: null, Controller: null, Events: null},
Our "controllers" Pyramid Object is composed of the class constructors for Clicks, Controller and Events.
This organises our classes into 2 "Pyramid Object" packages, "models" and "controllers". It not only documents the design, it will encapsulate them in stone. Nothing in "models" may reference anything in "controllers", and vice versa.
(function () {//Anonymous Closure
models.Model = jsface.Class(function () { //add constructor to Pyramid Object
var t
return (BallModel, {
constructor: function (controller) {
t = this
t.scenario = new models.Scenario(t, controller)//use the "model" constructor
t.targets = new models.Targets(t, controller)
t.elevation = new models.Turret('elevationTurret', 20)
t.gunRange = new models.GunRange(t, controller)
radio("elevationSpriteEvent").subscribe([t.elevation.setSprite, t.elevation]) //pubsub
delete models.Model
}
});
})()
}()); //END CLOSURE
Our Model class instantiates itself and the other member of the Pyramid Object. The last act of the constructor is to delete itself from the "models" object. Since there is an anonymous closure around Model is is now cemented shut. Nothing can reference it at all.
(function () {//Anonymous Closure
models.Scenario = jsface.Class(Sbox, function () { //add constructor to Pyramid Object
function isLastScenario(scenarioNum) {
if (firstTime)
return false
else
return scenarioNum === t.arr.length
}
return {//t.theRange, t.targets.arr,
constructor: function (modelP, controllerP) {
t = this
model = modelP
controller = controllerP
radio("nextTargetEvent").subscribe([nextTarget, this])
radio("startScenarioEvent").subscribe([startScenario, this])
delete models.Scenario //remove the "model" constructor,
}
});
}()); //END CLOSURE
All the classes in the "models" object delete themselves from the object.
Now the Pyramid object is empty:
So nothing can reference anything outside its own class. Which isn't much good, so we use a
Publish–subscribe pattern "radio.js" so the occupants of the pyramids can call each other.
The classes here use the jsface.js library, it doesn't matter how you implement classes here.
As shown, you can only have one instance of each class. If you want several instances of one class, leave out the "delete" in the classes constructor and clear the Pyramid object later on:
deleteProperties: function (obj) {
for (var x in obj)
if (obj.hasOwnProperty(x))
delete obj[x];
}
t.deleteProperties(models)
t.deleteProperties(controllers)