exercise3.js
JavaScript/modules/module2-intermediate/code-examples/lesson5/exercise3.js
// Exercise 3: Advanced OOP Concepts
// This exercise demonstrates advanced object-oriented programming concepts
console.log("=== Exercise 3: Advanced OOP Concepts ===");
// Example 1: Abstract-like behavior with base class
console.log("\n=== Abstract-like Base Class ===");
class Shape {
constructor(name) {
this.name = name;
}
// This method should be overridden by subclasses
calculateArea() {
throw new Error("calculateArea() must be implemented by subclass");
}
// This method should be overridden by subclasses
calculatePerimeter() {
throw new Error("calculatePerimeter() must be implemented by subclass");
}
getInfo() {
return `${this.name} - Area: ${this.calculateArea()}, Perimeter: ${this.calculatePerimeter()}`;
}
}
// Rectangle class extending Shape
class Rectangle extends Shape {
constructor(width, height) {
super("Rectangle");
this.width = width;
this.height = height;
}
calculateArea() {
return this.width * this.height;
}
calculatePerimeter() {
return 2 * (this.width + this.height);
}
}
// Circle class extending Shape
class Circle extends Shape {
constructor(radius) {
super("Circle");
this.radius = radius;
}
calculateArea() {
return Math.PI * this.radius * this.radius;
}
calculatePerimeter() {
return 2 * Math.PI * this.radius;
}
}
// Testing Shape inheritance
console.log("Creating shapes...");
let rectangle = new Rectangle(5, 3);
let circle = new Circle(4);
console.log("Rectangle info:", rectangle.getInfo());
console.log("Circle info:", circle.getInfo());
// Example 2: Composition over inheritance
console.log("\n=== Composition Example ===");
class Engine {
constructor(type, horsepower) {
this.type = type;
this.horsepower = horsepower;
this.isRunning = false;
}
start() {
this.isRunning = true;
return `${this.type} engine started (${this.horsepower} HP)`;
}
stop() {
this.isRunning = false;
return `${this.type} engine stopped`;
}
getStatus() {
return `${this.type} engine - ${this.horsepower} HP - ${this.isRunning ? 'Running' : 'Stopped'}`;
}
}
class Wheel {
constructor(size, brand) {
this.size = size;
this.brand = brand;
}
rotate() {
return `Wheel rotating (${this.size}" ${this.brand})`;
}
getInfo() {
return `${this.size}" ${this.brand} wheel`;
}
}
class Vehicle {
constructor(brand, model, engine, wheels) {
this.brand = brand;
this.model = model;
this.engine = engine; // Composition
this.wheels = wheels; // Composition
this.speed = 0;
}
start() {
return `${this.brand} ${this.model}: ${this.engine.start()}`;
}
stop() {
this.speed = 0;
return `${this.brand} ${this.model}: ${this.engine.stop()}`;
}
accelerate() {
if (this.engine.isRunning) {
this.speed += 10;
return `${this.brand} ${this.model} accelerating to ${this.speed} mph`;
}
return "Start the vehicle first";
}
getVehicleInfo() {
return `${this.brand} ${this.model} with ${this.engine.getStatus()}`;
}
getWheelInfo() {
return this.wheels.map(wheel => wheel.getInfo()).join(', ');
}
}
// Creating vehicles using composition
let v8Engine = new Engine("V8", 400);
let wheels = [
new Wheel(18, "Michelin"),
new Wheel(18, "Michelin"),
new Wheel(18, "Michelin"),
new Wheel(18, "Michelin")
];
let vehicle = new Vehicle("Ford", "Mustang", v8Engine, wheels);
console.log("Vehicle info:", vehicle.getVehicleInfo());
console.log("Wheels:", vehicle.getWheelInfo());
console.log("Start:", vehicle.start());
console.log("Accelerate:", vehicle.accelerate());
console.log("Accelerate:", vehicle.accelerate());
console.log("Stop:", vehicle.stop());
// Example 3: Polymorphism
console.log("\n=== Polymorphism Example ===");
class Animal {
constructor(name) {
this.name = name;
}
makeSound() {
return `${this.name} makes a sound`;
}
move() {
return `${this.name} moves`;
}
}
class Dog extends Animal {
makeSound() {
return `${this.name} barks: Woof! Woof!`;
}
move() {
return `${this.name} runs`;
}
}
class Bird extends Animal {
makeSound() {
return `${this.name} chirps: Tweet! Tweet!`;
}
move() {
return `${this.name} flies`;
}
}
class Fish extends Animal {
makeSound() {
return `${this.name} bubbles silently`;
}
move() {
return `${this.name} swims`;
}
}
// Polymorphism in action
let animals = [
new Dog("Buddy"),
new Bird("Tweety"),
new Fish("Nemo"),
new Animal("Generic Animal")
];
console.log("Polymorphism demonstration:");
animals.forEach(animal => {
console.log(`${animal.name}: ${animal.makeSound()}`);
console.log(`${animal.name}: ${animal.move()}`);
console.log("---");
});
// Example 4: Encapsulation with private-like properties
console.log("\n=== Encapsulation Example ===");
class BankAccount {
constructor(accountNumber, ownerName, initialBalance = 0) {
this.accountNumber = accountNumber;
this.ownerName = ownerName;
this._balance = initialBalance; // Convention: underscore indicates "private"
this._transactions = [];
}
// Getter for balance (read-only access)
get balance() {
return this._balance;
}
// Getter for transactions (read-only access)
get transactions() {
return [...this._transactions]; // Return copy to prevent external modification
}
deposit(amount) {
if (amount > 0) {
this._balance += amount;
this._transactions.push({
type: 'deposit',
amount: amount,
date: new Date(),
balance: this._balance
});
return `Deposited $${amount}. New balance: $${this._balance}`;
}
return "Invalid deposit amount";
}
withdraw(amount) {
if (amount > 0 && amount <= this._balance) {
this._balance -= amount;
this._transactions.push({
type: 'withdrawal',
amount: amount,
date: new Date(),
balance: this._balance
});
return `Withdrew $${amount}. New balance: $${this._balance}`;
}
return "Insufficient funds or invalid amount";
}
getAccountSummary() {
return `Account ${this.accountNumber} (${this.ownerName}): $${this._balance}`;
}
}
// Testing encapsulation
let account = new BankAccount("ACC001", "Alice Johnson", 1000);
console.log("Account summary:", account.getAccountSummary());
console.log("Balance (getter):", account.balance);
console.log("Deposit:", account.deposit(500));
console.log("Withdraw:", account.withdraw(200));
console.log("Transactions:", account.transactions.length);
console.log("Final balance:", account.balance);
// Try to access "private" properties (this will work but is not recommended)
console.log("Direct access to _balance:", account._balance); // Not recommended
console.log("Direct access to _transactions:", account._transactions.length); // Not recommended
console.log("\n=== Advanced OOP Concepts Summary ===");
console.log("✓ Abstract-like behavior with base classes");
console.log("✓ Composition over inheritance");
console.log("✓ Polymorphism with method overriding");
console.log("✓ Encapsulation with private-like properties");
console.log("✓ Getters for controlled access to properties");
console.log("✓ Error handling in abstract methods");
Articles liés
exercise1.js
exercise1.js — javascript source code from the JavaScript learning materials (JavaScript/modules/module1-foundations/code-examples/lesson1/exercise1.js).
Lire l'article →exercise2.js
exercise2.js — javascript source code from the JavaScript learning materials (JavaScript/modules/module1-foundations/code-examples/lesson1/exercise2.js).
Lire l'article →exercise3.js
exercise3.js — javascript source code from the JavaScript learning materials (JavaScript/modules/module1-foundations/code-examples/lesson1/exercise3.js).
Lire l'article →hello.js
hello.js — javascript source code from the JavaScript learning materials (JavaScript/modules/module1-foundations/code-examples/lesson1/hello.js).
Lire l'article →exercise1.js
exercise1.js — javascript source code from the JavaScript learning materials (JavaScript/modules/module1-foundations/code-examples/lesson2/exercise1.js).
Lire l'article →exercise2.js
exercise2.js — javascript source code from the JavaScript learning materials (JavaScript/modules/module1-foundations/code-examples/lesson2/exercise2.js).
Lire l'article →