-
Notifications
You must be signed in to change notification settings - Fork 5
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
some code in Scene belongs in its subclasses #282
Comments
Signed-off-by: Chris Malley <cmalley@pixelzoom.com>
To clarify, and for the sake of discussion... Here's the anti-pattern used in class Scene {
constructor() {
if ( this instanceof WaveScene ) {
code that is specific to the Wave scene;
}
else if ( this instanceof SoundScene ) {
code that is specific to the Sound scene;
}
else {
code that is specific to the Light scene;
}
}
}
class WaveScene extends Scene { ... }
class SoundScene extends Scene { ... }
class LightScene extends Scene { ... } The current implementation of class Scene {
// @param {SceneType} sceneType
constructor( sceneType ) {
if ( sceneType === SceneType.WAVE ) {
code that is specific to the Wave scene;
}
else if ( sceneType === SceneType.SOUND ) {
code that is specific to the Sound scene;
}
else {
code that is specific to the Light scene;
}
}
}
class WaveScene extends Scene {
constructor() {
super( SceneType.WAVE );
}
}
class SoundScene extends Scene {
constructor() {
super( SceneType.SOUND );
}
}
class LightScene extends Scene {
constructor() {
super( SceneType.LIGHT );
}
} I'll be happy to discuss, but I don't know of any good argument for using the above patterns in OO programming. The 3 most common JS patterns for extending a superclass with subclass-specific function are as follows. Pretty basic OO stuff here, but worth repeating. You may need to use one or all of these to untangle (1) All subclasses implement a method that is declared abstract in the superclass. class Scene {
constructor() {
someFunction();
}
// @abstract
someFunction() {
throw new Error( 'subclass must implement someFunction' );
}
}
class WaveScene extends Scene {
// @override
someFunction() {
code that is specific to the Wave scene;
}
}
class SoundScene extends Scene {
// @override
someFunction() {
code that is specific to the Sound scene;
}
}
class LightScene extends Scene {
// @override
someFunction() {
code that is specific to the Light scene;
}
} (2) Subclasses override and extend a concrete method implemented in the superclass. A variation on this is to fully replace the superclass method by not chaining to class Scene {
constructor() {
someFunction();
}
someFunction() {
code that is relevant to all Scenes;
}
}
class WaveScene extends Scene {
// @override
someFunction() {
super.someFunction();
code that is specific to the Wave scene;
}
}
class SoundScene extends Scene {
// @override
someFunction() {
super.someFunction();
code that is specific to the Sound scene;
}
}
class LightScene extends Scene {
// @override
someFunction() {
super.someFunction();
code that is specific to the Light scene;
}
} (3) Subclasses provide functionality via constructor parameters (if functionality is required) or options (if functionality is optional). class Scene {
// @param {function} someFunction
constructor( someFunction ) {
someFunction();
}
}
class WaveScene extends Scene {
constructor() {
super( () => { code that is specific to the Wave scene; } );
}
}
class SoundScene extends Scene {
constructor() {
super( () => { code that is specific to the Sound scene; } );
}
}
class LightScene extends Scene {
constructor() {
super( () => { code that is specific to the Light scene; } );
}
} |
Good recommendation, proposed fix committed, please review. |
Very nice, much easier to grok. A couple of last nits in
setSourceValues() {
// Get the desired amplitude. For water, this is set through the desiredAmplitudeProperty. For other
// scenes, this is set through the amplitudeProperty.
const amplitude = this.desiredAmplitudeProperty ? this.desiredAmplitudeProperty.get() : this.amplitudeProperty.get();
const time = this.timeProperty.value;
if ( this.waveSpatialType === WaveSpatialTypeEnum.POINT ) {
this.getPointSourceValues( amplitude, time );
}
else {
this.getPlaneSourceValues( amplitude, time );
}
} |
Good ideas, I've done so in the preceding commit. Please review. |
👍 Closing. |
Related to code review #259. This originally was a REVIEW comment, promoting to an issue.
Here's the relevant code and REVIEW comment thread:
The "requirejs loop" comment made me take a closer look at
Scene
. The uses ofSceneType
therein have a code smell to them. This is a case of a base class (Scene
) containing code that is specific to subclasses (WaterScene
,SoundScene
,LightScene
). It violates this code-review item:One example from
Scene
, line 180:The
if ( config.sceneType !== SceneType.WATER ) {...}
bit belongs inWaterScene
, not inScene
.Recommended to address this by (1) eliminating
SceneType
enum, and (2) moving subclass-specific code to the appropriate subclass. This is unfortunately not a trivial change, butScene
is so fundamental that it's worth doing.The text was updated successfully, but these errors were encountered: