Skip to content

Commit 28a2988

Browse files
authored
revise DI description with MAL setter example, see #88
1 parent 0e651de commit 28a2988

File tree

1 file changed

+5
-39
lines changed

1 file changed

+5
-39
lines changed

doc/phet-software-design-patterns.md

+5-39
Original file line numberDiff line numberDiff line change
@@ -166,51 +166,17 @@ This takes advantage of the fact that while each argument has a `toString` metho
166166

167167
-------------
168168

169-
We already see a lot of straightforward DI at PhET such as passing `model` or `Property` instances as constructor arguments or in our `options` and `config` objects. The issue (as presented in https://github.com/phetsims/tasks/issues/952) is in places where we have a composite Node/object and when such types should use DI or initialize their instance variables internally.
169+
We already see a lot of straightforward DI at PhET such as passing `model` or `Property` instances as constructor arguments or in our `options` and `config` objects. How PhET handles DI is largely up to the developer and we can find instances of each flavor in our codebase; however, we most commonly see dependencies passed either as constructor arguments or within our options/config objects. When deciding what approach to take, it's generally a good idea to examine the those objects for their complexity. Large, heavily nested options objects are a relatively good indicator that DI may simplify your implementation.
170170

171-
A simple example would be a Node that had a `Text` object and a `Button` object as its children and we want to expose adding a push handler to the client code.
171+
To start, [Molecules and Light](https://github.com/phetsims/molecules-and-light) employs setter injection in how it handles absorption of various wavelengths of light for different molecules.
172172

173-
```js
174-
class ButtonAndText extends Node {
175-
176-
constructor() {
177-
super();
178-
this.textNode = new Text( 'some text' );
179-
this.button = new RoundPushButton( {
180-
radius: ...,
181-
content: ...,
182-
baseColor: ...,
183-
touchAreaDilation: ...
184-
} );
185-
this.children = [ this.textNode, this.button ];
186-
}
187-
188-
addPushListener( handler ) {
189-
this.button.addListener( handler );
190-
}
191-
}
192-
```
193-
194-
vs
173+
In [Molecule.js](https://github.com/phetsims/molecules-and-light/blob/master/js/photon-absorption/model/Molecule.js), the constructor initializes `this.mapWavelengthToAbsorptionStrategy = {}`. Then on ln 189, we have the following method allows any object inheriting Molecule to dynamically set the necessary `PhotonAbsorptionStrategy`
195174

196175
```js
197-
class ButtonAndText extends Node {
198-
constructor( textNode, roundPushButton ) {
199-
super();
200-
this.textNode = textNode;
201-
this.roundPushButton = roundPushButton;
202-
this.children = [ this.textNode, this.roundPushButton ];
203-
}
204-
205-
// can also add the listener here
206-
addPushListener( handler ) {
207-
this.button.addListener( handler );
208-
}
176+
setPhotonAbsorptionStrategy( wavelength, strategy ) {
177+
this.mapWavelengthToAbsorptionStrategy[ wavelength ] = strategy;
209178
}
210179
```
211-
Note: Since JS doesn't have strict privacy on object methods & properties (i.e. `new ButtonAndText().button.addListener( ... )` is allowed), this boils down to a convention we'd like to see implemented as opposed to a hard requirement of the language.
212-
213-
The complication really arises from what can be done when the button is pushed. Perhaps it creates and appends a new `Shape` or contextually adds a new `Button` to perform some other action.
214180

215181
## Dispose
216182

0 commit comments

Comments
 (0)