Skip to main content
Ben Nadel at InVision In Real Life (IRL) 2019 (Phoenix, AZ) with: Ben Michel and Boaz Ruck
Ben Nadel at InVision In Real Life (IRL) 2019 (Phoenix, AZ) with: Ben Michel ( @obensource ) Boaz Ruck

Using Static Class Methods To Generate Concrete Instances Of Abstract Classes In JavaScript And Node.js

By on

The other day, I was building a JavaScript class that depended on another Abstract class as an injected value. The Abstract class only exposed one abstract method that needed to be overridden in a sub-class. I know that not everyone - especially in the Node.js community - is so hot on writing Classes; so, I wanted to see if I could provide a workflow that could consume just the concrete method without having to define an entire sub-class. To do this, I created a static factory function on the abstract class that merged the concrete method into the abstract instance.

JavaScript is enchantingly dynamic (and that's before you even get to ES6 Proxy objects). You can create objects from Prototypes; you can manually construct objects by weaving properties together; or, you can do a little of this and a little of that. And, it's this last approach that I am using in my static factory function. Rather than defining a sub-class, I'm just instantiating the abstract class (because "Abstract" isn't a formal part of the JavaScript language); and then, I'm manually injecting the concrete methods into the abstract instance, thereby "completing" it:

class AbstractThing {

	// ---
	// ABSTRACT METHODS.
	// ---

	doThis() {
		throw( new Error( "Abstract method." ) );
	}

	doThat() {
		throw( new Error( "Abstract method." ) );
	}

	// ---
	// PUBLIC METHODS.
	// ---

	execute() {
		this.doThis();
		this.doThat();
	}

	// ---
	// STATIC METHODS.
	// ---

	// I provide a way to create a concrete implementation of the AbstractThing class
	// by providing the concrete functions. This is in lieu of creating a base class that
	// extends the AbstractThing class explicitly.
	static usingFunctions({ doThis, doThat }) {

		var implementation = new AbstractThing();

		// Override the abstract methods with the given concrete functions.
		implementation.doThis = doThis;
		implementation.doThat = doThat;

		return( implementation );

	}

}

// ----------------------------------------------------------------------------------- //
// ----------------------------------------------------------------------------------- //

// Create a concrete instance using the two concrete methods (no base class needed).
var thing = AbstractThing.usingFunctions({
	doThis: function() {
		console.log( "... do this." );
	},
	doThat: function() {
		console.log( "... do that." );
	}
});

console.log( "Is instance of AbstractThing:", ( thing instanceof AbstractThing ) );
thing.execute();

As you can see, the AbstractThing class requires two methods to be overridden in its sub-classes: doThis() and doThat(). The static method, usingFunctions(), takes these two required methods, instantiates the AbstractThing class and then, manually overrides the abstract methods with the given concrete ones.

When we run this code though Node.js, we get the following terminal output:

Using static methods to generate concrete instances of abstract classes in JavaScript.

Works like a charm. There's no magic here, really. This is just JavaScript being JavaScript, which is why JavaScript is so awesome. Of course, this approach only works if there's no additional constructor logic needed by the concrete class. But, if you only need to provide one or two functions (which can be powered by lexical scoping rather than constructor arguments), this seems like a fun little pattern to use.

Want to use code from this post? Check out the license.

Reader Comments

I believe in love. I believe in compassion. I believe in human rights. I believe that we can afford to give more of these gifts to the world around us because it costs us nothing to be decent and kind and understanding. And, I want you to know that when you land on this site, you are accepted for who you are, no matter how you identify, what truths you live, or whatever kind of goofy shit makes you feel alive! Rock on with your bad self!
Ben Nadel