diff --git a/oop/Abstraction.ts b/oop/Abstraction.ts new file mode 100644 index 00000000..8757a71d --- /dev/null +++ b/oop/Abstraction.ts @@ -0,0 +1,36 @@ +/** + * @concept Abstraction + * + * Abstraction is a fundamental Object-Oriented Programming concept that hides + * complex implementation details and exposes only the necessary features + * of an object. It allows you to focus on what an object does instead of + * how it does it. + * + * @see {@link https://en.wikipedia.org/wiki/Abstraction_(computer_science) | Wikipedia: Abstraction} + * @see {@link https://www.typescriptlang.org/docs/handbook/2/classes.html#abstract-classes-and-members | TypeScript Docs: Abstract Classes} + */ +export abstract class MailService { + /** + * Abstract method definition. + * Subclasses must implement this method to provide specific mail delivery logic. + */ + abstract send(): void; + + /** + * Shared internal logic available to all subclasses, + * abstracting away the connection process. + */ + protected connect(): void { + console.log("Connecting to mail server..."); + } +} + +/** + * Concrete implementation of the abstract MailService. + */ +export class GmailService extends MailService { + send(): void { + this.connect(); + console.log("Sending mail via Gmail..."); + } +} \ No newline at end of file diff --git a/oop/Encapsulation.ts b/oop/Encapsulation.ts new file mode 100644 index 00000000..ce247f6c --- /dev/null +++ b/oop/Encapsulation.ts @@ -0,0 +1,33 @@ +/** + * @concept Encapsulation + * + * Encapsulation is the bundling of data (properties) and the methods + * that operate on that data within a single unit or class. It restricts + * direct external access to the object's internal state, promoting + * data integrity and security. + * + * @see {@link https://en.wikipedia.org/wiki/Encapsulation_(computer_programming) | Wikipedia: Encapsulation} + * @see {@link https://www.typescriptlang.org/docs/handbook/2/classes.html#member-visibility | TypeScript Docs: Member Visibility} + */ +export class SmartWatch { + /** + * Private internal state, inaccessible directly from outside the class. + */ + private _stepCount: number = 0; + + /** + * Controlled public interface to safely modify the internal state. + * @param steps - The number of steps to add. + */ + public addSteps(steps: number): void { + if (steps > 0) this._stepCount += steps; + } + + /** + * Public getter to safely retrieve the internal state without allowing direct modification. + * @returns The current step count. + */ + public get steps(): number { + return this._stepCount; + } +} \ No newline at end of file diff --git a/oop/Inheritance.ts b/oop/Inheritance.ts new file mode 100644 index 00000000..084962c7 --- /dev/null +++ b/oop/Inheritance.ts @@ -0,0 +1,33 @@ +/** + * @concept Inheritance + * + * Inheritance is a mechanism where a new class (subclass) acquires the + * properties and methods of an existing class (superclass). It promotes + * code reusability and establishes a hierarchical relationship between classes. + * + * @see {@link https://en.wikipedia.org/wiki/Inheritance_(object-oriented_programming) | Wikipedia: Inheritance} + * @see {@link https://www.typescriptlang.org/docs/handbook/2/classes.html#extends-clauses | TypeScript Docs: Extends Clauses} + */ +export class User { + constructor(public name: string) { } + + /** + * Common method available to all Users and their subclasses. + */ + login(): void { + console.log(`${this.name} logged in.`); + } +} + +/** + * Admin inherits the properties (name) and methods (login) from User, + * while defining its own specialized behaviors. + */ +export class Admin extends User { + /** + * Specialized method only available to Admins. + */ + deleteUser(userName: string): void { + console.log(`Admin ${this.name} is deleting user: ${userName}`); + } +} \ No newline at end of file diff --git a/oop/Polymorphism.ts b/oop/Polymorphism.ts new file mode 100644 index 00000000..ae927687 --- /dev/null +++ b/oop/Polymorphism.ts @@ -0,0 +1,34 @@ +/** + * @concept Polymorphism + * + * Polymorphism (meaning "many forms") allows objects of different classes + * to be treated as objects of a common superclass or interface. It enables + * a single interface to represent different underlying forms (data types). + * + * @see {@link https://en.wikipedia.org/wiki/Polymorphism_(computer_science) | Wikipedia: Polymorphism} + * @see {@link https://www.typescriptlang.org/docs/handbook/2/classes.html#implements-clauses | TypeScript Docs: Implements Clauses} + */ +export interface UIElement { + /** + * Common interface method that all implementing classes must define. + */ + render(): void; +} + +/** + * Specific implementation of UIElement behaving as a TextBox. + */ +export class TextBox implements UIElement { + render(): void { + console.log("Rendering a TextBox"); + } +} + +/** + * Specific implementation of UIElement behaving as a Checkbox. + */ +export class Checkbox implements UIElement { + render(): void { + console.log("Rendering a Checkbox"); + } +} \ No newline at end of file diff --git a/oop/test/OOP.test.ts b/oop/test/OOP.test.ts new file mode 100644 index 00000000..78ac7789 --- /dev/null +++ b/oop/test/OOP.test.ts @@ -0,0 +1,50 @@ +import { MailService, GmailService } from '../Abstraction'; +import { SmartWatch } from '../Encapsulation'; +import { User, Admin } from '../Inheritance'; +import { UIElement, TextBox, Checkbox } from '../Polymorphism'; + +describe('TypeScript OOP Educational Examples', () => { + test('Abstraction: Should correctly use MailService and GmailService', () => { + const gmail = new GmailService(); + const spy = jest.spyOn(console, 'log'); + + gmail.send(); + + expect(spy).toHaveBeenCalledWith("Connecting to mail server..."); + expect(spy).toHaveBeenCalledWith("Sending mail via Gmail..."); + spy.mockRestore(); + }); + + test('Encapsulation: Should protect internal step count', () => { + const watch = new SmartWatch(); + watch.addSteps(100); + expect(watch.steps).toBe(100); + + watch.addSteps(-50); // should not reduce steps because step must be > 0 + expect(watch.steps).toBe(100); + // watch._stepCount is inaccessible here (TypeScript error) + }); + + test('Inheritance: Should allow Admin to inherit User and have custom behavior', () => { + const admin = new Admin("Alice"); + const spy = jest.spyOn(console, 'log'); + + admin.login(); + admin.deleteUser("Bob"); + + expect(spy).toHaveBeenCalledWith("Alice logged in."); + expect(spy).toHaveBeenCalledWith("Admin Alice is deleting user: Bob"); + spy.mockRestore(); + }); + + test('Polymorphism: Should work with different UIElement types', () => { + const elements: UIElement[] = [new TextBox(), new Checkbox()]; + const spy = jest.spyOn(console, 'log'); + + elements.forEach(el => el.render()); + + expect(spy).toHaveBeenCalledWith("Rendering a TextBox"); + expect(spy).toHaveBeenCalledWith("Rendering a Checkbox"); + spy.mockRestore(); + }); +}); \ No newline at end of file