Table of Contents
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
how to derive a JS class model, and a corresponding entity table model, from the information design model,
how to code the JS class model in the form of JS model classes,
how to write the view and controller code based on the model code.
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})
.