Chapter 17. Subtyping with Plain JS

Table of Contents

1. Subtyping with ES6 Classes
2. Case Study 1: Eliminating a Class Hierarchy
2.1. Make the JS class model
2.2. New issues
2.3. Code the model classes of the JS class model
2.4. Write the User Interface Code
3. Case Study 2: Implementing a Class Hierarchy
3.1. Make a JS class model
3.2. Make a JS entity table model
3.3. New issues
3.4. Code the model classes of the JS class model
3.5. Take care of subtypes in the UI
4. Quiz Questions
4.1. Question 1: Defining a Subclass
4.2. Question 2: Merging Subclasses
4.3. Question 3: Check Method for Segment Property

Whenever an app has to manage the data of a larger number of object types, there may be various subtype (inheritance) relationships between some of the object types. Handling subtype relationships is an advanced issue in software application engineering, which is often not well supported by application development frameworks.

In this chapter, we first explain the general approach to constructor-based subtyping in JavaScript before presenting two case studies based on fragments of the information model of our running example, the Public Library app, shown above.

In the first case study, we consider the single-level class hierarchy with root Book shown in Figure 16.1, which is an incomplete disjoint rigid segmentation. We use the Class Hierarchy Merge design pattern for re-factoring this simple class hierarchy to a single class that can be mapped to a persistent database table.

In the second case study, we consider the multi-level class hierarchy consisting of the Person roles Employee, Manager and Author, shown in Figure 16.8. The segmentation of Person into Employee and Author does not have any constraints, which means that it is incomplete, overlapping (non-disjoint) and non-rigid.

We use the Class Hierarchy Merge design pattern for re-factoring the simple Manager-is-Employee sub-hierarchy, and the Joined Tables Inheritance approach for mapping the Employee-and-Author-is-a-Person class hierarchy to a set of three database tables that are related with each other via foreign key dependencies.

In both case studies we show

  1. how to derive a JS class model, and a corresponding entity table model, from the information design model,

  2. how to code the JS class model in the form of JS model classes,

  3. how to write the view and controller code based on the model code.

1. Subtyping with ES6 Classes

Before the version ES6 (or ES2015), JavaScript did not have an explicit class concept and subtyping was not directly supported, so it had to be implemented with the help of certain code patterns providing two inheritance mechanisms: (1) inheritance of properties and (2) inheritance of methods.

As we have explained in Section 1.10 , classes can be defined in two alternative ways: constructor-based and factory-based. Both approaches have their own way of implementing inheritance.

We summarize the ES6 code pattern for defining a superclass and a subclass in a constructor-based single-inheritance class hierarchy with the help of the following example:

First, we define a base class, Person, with two properties, firstName and lastName, defined with getters and setters:

class Person {
  constructor ({first, last}) {
    // assign properties by invoking their setters
    this.firstName = first; 
    this.lastName = last; 
  }
  get firstName() {return this._firstName;}
  set firstName( f) {
    ... // check constraints
    this._firstName = f;
  }
  get lastName() {return this._lastName;}
  set lastName( l) {
    ... // check constraints
    this._lastName = l;
  }
}

Then, we define a subclass, Student, with one additional property, studNo, using the ES6 keywords extends and super:

class Student extends Person {
  constructor ({first, last, studNo}) {
    // invoke constructor of superclass
    super({first, last});
    // assign additional properties
    this.studNo = studNo;
  }
  get studNo() {return this._studNo;}
  set studNo( sn) {
    ... // check constraints
    this._studNo = sn;
  }
}

Notice how the constructor of the superclass Person is invoked: with super({first, last}).