Inheritance: Extend a Compatible Contract
Specialize a school notice without changing its promise
A report displays different notice objects by asking each for text. An urgent notice should still provide text, while specializing the message it returns.
Inheritance lets a subclass reuse and specialize behavior from a parent class. A useful child remains compatible with the parent’s promised interface.
Read the relationship
Identify parent and subclass.
Trace an override
Explain which implementation a call uses.
Compare composition
Recognize when receiving a helper is more flexible than subclassing.
An urgent notice keeps the text contract
Parent contract
A notice supplies a string message.
text()Specialized class
An urgent notice changes the wording.
override text()Caller
Use the same operation on the specialized object.
Urgent: Library closed
A child must be usable where the parent is promised
JavaScript extends declares the parent relationship. A method with the same name can override the inherited implementation. The caller invokes the receiver’s applicable implementation.
Inheritance is not just a device to avoid copying lines. If a child changes accepted inputs or result meaning incompatibly, it can break callers expecting the parent’s contract. Favor shallow, understandable relationships.
Before starting, review classes and methods. These examples use JavaScript; other languages can use different syntax and rules.
Use both notices through one operation
The ordinary instance returns Notice. The specialized instance returns the urgent message because its method overrides the parent method.
Both return strings, so the report can display them with the same call pattern. JavaScript does not require a formal interface declaration for this example.
JavaScript · local teaching example
class Notice {
text() { return 'Notice'; }
}
class UrgentNotice extends Notice {
text() { return 'Urgent: Library closed'; }
}
const notices = [new Notice(), new UrgentNotice()];
for (const notice of notices) console.log(notice.text());Expected output
Notice
Urgent: Library closedA helper can supply behavior without a subclass
Composition combines objects or functions as collaborators. Here the notice receives the message-producing function rather than inheriting a separate class for every wording.
This can make independent choices easier to combine. It still needs a clear collaborator contract; dependency injection is not automatic correctness.
JavaScript · local teaching example
class Notice {
constructor(message) { this.message = message; }
text() { return this.message(); }
}
const notice = new Notice(() => 'Library opens at 9');
console.log(notice.text());Expected output
Library opens at 9Apply the rule to a small change
Create a ReminderNotice subclass returning “Bring your library card” and call its text method.
Worked answer
The reminder changes the message while preserving the string-returning text operation. It does not need to override unrelated behavior.
JavaScript · local teaching example
class Notice { text() { return 'Notice'; } }
class ReminderNotice extends Notice {
text() { return 'Bring your library card'; }
}
console.log(new ReminderNotice().text());Expected output
Bring your library cardRecognize mistakes and limits
A subclass constructor must call super before using this in JavaScript. That initializes the parent portion of the instance. Do not duplicate parent initialization blindly.
Avoid deep trees that encode unrelated dimensions, such as urgent plus emailed plus translated. Composition can combine independent features more clearly. If a subtype cannot honor the parent contract, reconsider the relationship.
For the language or tool rules used here, see JavaScript class behavior.
Check the core idea
JavaScript · code for this question
class Notice {
text() { return 'Notice'; }
}
class UrgentNotice extends Notice {
text() { return 'Urgent: Library closed'; }
}
const notices = [new Notice(), new UrgentNotice()];
for (const notice of notices) console.log(notice.text());Apply the idea to a new situation
Extend a promise, not just a code fragment
Inheritance specializes compatible behavior. Trace overrides, preserve input and result contracts, and compare composition when independent features need combining.
Connect this idea with common operations with different implementations and composition and responsibility.
Reaching the recap and completing the quizzes are separate milestones.