Add section on roles

This commit is contained in:
Victor Woeltjen
2015-12-22 13:13:00 -08:00
parent c99b6df9fc
commit 0d2b5160ac
2 changed files with 138 additions and 7 deletions

View File

@ -34,14 +34,12 @@ Note that additional developer use cases may be supported by using the
more general-purpose `Registry` more general-purpose `Registry`
```nomnoml ```nomnoml
[Function.<T, V>]
[Factory.<T, V> [Factory.<T, V>
| |
- factoryFn : Function.<T, V> - factoryFn : function (V) : T
| |
+ decorate(decoratorFn : Function.<T, T>, options? : RegistrationOptions) + decorate(decoratorFn : function (T, V) : T, options? : RegistrationOptions)
]-:>[Function.<T, V>] ]-:>[function (V) : T]
[RegistrationOptions | [RegistrationOptions |
+ priority : number or string + priority : number or string
@ -49,10 +47,10 @@ more general-purpose `Registry`
[Registry.<T, V> [Registry.<T, V>
| |
- compositorFn : Function.<V, Array.<T>> - compositorFn : function (Array.<T>) : V
| |
+ register(item : T, options? : RegistrationOptions) + register(item : T, options? : RegistrationOptions)
+ composite(compositorFn : Function.<V, Array.<T>>, options? : RegistrationOptions) + composite(compositorFn : function (Array.<T>) : V, options? : RegistrationOptions)
]-:>[Factory.<V, Void>] ]-:>[Factory.<V, Void>]
[Factory.<V, Void>]-:>[Factory.<T, V>] [Factory.<V, Void>]-:>[Factory.<T, V>]
@ -162,3 +160,5 @@ myModule.hamburgers = new mct.ExtensionRegistry();
to an extension or service. But, passing these in as constructor to an extension or service. But, passing these in as constructor
arguments is preferred (to separate implementation from architecture.) arguments is preferred (to separate implementation from architecture.)
* Adds (negligible?) boilerplate relative to declarative syntax. * Adds (negligible?) boilerplate relative to declarative syntax.
* Relies on factories, increasing number of interfaces to be concerned
with.

View File

@ -0,0 +1,131 @@
# Roles
Roles are presented as an alternative formulation to capabilities
(dynamic behavior associated with individual domain objects.)
Specific goals here:
* Dependencies of individual scripts should be clear.
* Domain objects should be able to selectively exhibit a wide
variety of behaviors.
## Developer Use Cases
1. Checking for the existence of behavior.
2. Using behavior.
3. Augmenting existing behaviors.
4. Overriding existing behaviors.
5. Adding new behaviors.
## Overview of Proposed Solution
Remove `getCapability` from domain objects; add roles as external
services which can be applied to domain objects.
## Interfaces
```nomnoml
[Factory.<T, V>
|
- factoryFn : function (V) : T
|
+ decorate(decoratorFn : function (T, V) : T, options? : RegistrationOptions)
]-:>[function (V) : T]
[RegistrationOptions |
+ priority : number or string
]
[Role.<T> |
+ validate(domainObject : DomainObject) : boolean
]-:>[Factory.<T, DomainObject>]
[Factory.<T, DomainObject>]-:>[Factory.<T, V>]
```
## Examples
### 1. Checking for the existence of behavior
```js
function PlotViewPolicy(telemetryRole) {
this.telemetryRole = telemetryRole;
}
PlotViewPolicy.prototype.allow = function (view, domainObject) {
return this.telemetryRole.validate(domainObject);
};
```
### 2. Using behavior
```js
PropertiesAction.prototype.perform = function () {
var mutation = this.mutationRole(this.domainObject);
return this.showDialog.then(function (newModel) {
return mutation.mutate(function () {
return newModel;
});
});
};
```
### 3. Augmenting existing behaviors
```js
// Non-Angular style
mct.roles.persistenceRole.decorate(function (persistence) {
return new DecoratedPersistence(persistence);
});
// Angular style
myModule.decorate('persistenceRole', ['$delegate', function ($delegate) {
return new DecoratedPersistence(persistence);
}]);
```
### 4. Overriding existing behaviors
```js
// Non-Angular style
mct.roles.persistenceRole.decorate(function (persistence, domainObject) {
return domainObject.getModel().type === 'someType' ?
new DifferentPersistence(domainObject) :
persistence;
});
```
### 5. Adding new behaviors
```js
function FooRole() {
mct.Role.apply(this, [function (domainObject) {
return new Foo(domainObject);
}]);
}
FooRole.prototype = Object.create(mct.Role.prototype);
FooRole.prototype.validate = function (domainObject) {
return domainObject.getModel().type === 'some-type';
};
//
myModule.roles.fooRole = new FooRole();
```
## Evaluation
### Benefits
* Simplifies/standardizes augmentation or replacement of behavior associated
with specific domain objects.
* Minimizes number of abstractions; roles are just factories.
* Clarifies dependencies; roles used must be declared/acquired in the
same manner as services.
### Detriments
* Externalizes functionality which is conceptually associated with a
domain object.
* Relies on factories, increasing number of interfaces to be concerned
with.