From 0d2b5160ac419f985a00f6ddd1980f1eef060d32 Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Tue, 22 Dec 2015 13:13:00 -0800 Subject: [PATCH] Add section on roles --- .../src/design/proposals/ImperativePlugins.md | 14 +- docs/src/design/proposals/Roles.md | 131 ++++++++++++++++++ 2 files changed, 138 insertions(+), 7 deletions(-) create mode 100644 docs/src/design/proposals/Roles.md diff --git a/docs/src/design/proposals/ImperativePlugins.md b/docs/src/design/proposals/ImperativePlugins.md index c93fb48390..1fbb83b1bc 100644 --- a/docs/src/design/proposals/ImperativePlugins.md +++ b/docs/src/design/proposals/ImperativePlugins.md @@ -34,14 +34,12 @@ Note that additional developer use cases may be supported by using the more general-purpose `Registry` ```nomnoml -[Function.] - [Factory. | - - factoryFn : Function. + - factoryFn : function (V) : T | - + decorate(decoratorFn : Function., options? : RegistrationOptions) -]-:>[Function.] + + decorate(decoratorFn : function (T, V) : T, options? : RegistrationOptions) +]-:>[function (V) : T] [RegistrationOptions | + priority : number or string @@ -49,10 +47,10 @@ more general-purpose `Registry` [Registry. | - - compositorFn : Function.> + - compositorFn : function (Array.) : V | + register(item : T, options? : RegistrationOptions) - + composite(compositorFn : Function.>, options? : RegistrationOptions) + + composite(compositorFn : function (Array.) : V, options? : RegistrationOptions) ]-:>[Factory.] [Factory.]-:>[Factory.] @@ -162,3 +160,5 @@ myModule.hamburgers = new mct.ExtensionRegistry(); to an extension or service. But, passing these in as constructor arguments is preferred (to separate implementation from architecture.) * Adds (negligible?) boilerplate relative to declarative syntax. +* Relies on factories, increasing number of interfaces to be concerned + with. \ No newline at end of file diff --git a/docs/src/design/proposals/Roles.md b/docs/src/design/proposals/Roles.md new file mode 100644 index 0000000000..13742bec4f --- /dev/null +++ b/docs/src/design/proposals/Roles.md @@ -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. + | + - factoryFn : function (V) : T + | + + decorate(decoratorFn : function (T, V) : T, options? : RegistrationOptions) +]-:>[function (V) : T] + +[RegistrationOptions | + + priority : number or string +] + +[Role. | + + validate(domainObject : DomainObject) : boolean +]-:>[Factory.] +[Factory.]-:>[Factory.] +``` + +## 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. \ No newline at end of file