Ways to Implement Dependency Inversion Principle in AngularJS
Case Study: The Mediator Pattern
Normally, implementing a Mediator/Director entails both Director and Colleague(s) having a reference to each other. Not difficult when Director is responsible for Module-Lifecycle Management (MLM):
Director creates Colleagues while passing itself in during construction:
var Director = function Director($$) {
...
function init(...) {
_moduleA = new ModuleA(this);
_moduleB = new ModuleX(this);
_moduleX = new ModuleX(this);
}
function moduleChanged(ref) {
if (ref === _moduleXYZ) _moduleC.run(ref.datum);
}
return this;
};
The Tricky Part: Angular
AngularJS automatically takes on the burden of MLM, so its tough to use the approach above. We could modify our Director.init method slightly:
_moduleX = $dependency;
...
_moduleX.init(this);
But [my] Colleagues need a reference to Director at construction-time.
Question and Explanation
While my Director is implemented as EDM (Event-Driven Mediation) to run away from needing DIP, I now need Colleagues to reference Director:
var Colleague = function Colleague(director) {
var thus = this;
...
director.publish(director.CHANNELS.SOME_CHANNEL_NAME, data);
...
return this;
};
Because Director must now provide Module Authorization (MA):
var Director = function Director($$) {
...
function subscribe(channel, handler) {
var args = Array.prototype.slice.call(arguments, 0);
$rootScope.$on.apply($rootScope, args);
return this;
}
function publish(channel) {
var args = Array.prototype.slice.call(arguments, 0);
if (channel in this.CHANNELS.SOME_CHANNEL_NAME) $rootScope.$broadcast.apply($rootScope, args);
return this;
}
return this;
};
That said, there's virtually NO-DIFFERENCE -- as far as DIP/DI is concerned -- between this approach and the more Classical, object-reference driven approach first mentioned.
So my question is, what are different ways that I can elegantly impose DIP and MLM in Angular without running into problems with the framework?
Concerns & Potential Workarounds
_colleague.init(this);: BAD_colleague = Colleague.call($dependency, this): Healthy for Singletons???- Mediator Abstract Class [SEE below]
Abstract Mediator Class
As in GoF, the Participants include a Mediator and a ConcreteMediator.
-
Mediator:
- Defines an Interface for communication with Colleague objects
-
ConcreteMediator:
- Implements cooperative behavior by coordinating Colleague objects
- knows and maintains its colleagues
To follow a little closer to DIP, can we take "this.CHANNELS" and apply it to Mediator, but ConcreteMediator would still need a reference to it and Colleague would need a reference to whatever is providing both .CHANNELS and .publish(...).
Any ideas or patterns you've used or can think of?
#PreThanks
Aucun commentaire:
Enregistrer un commentaire