Skip to content

Commit a8da1ef

Browse files
committed
feat: update OOP exercises with enhanced class structures, method overrides, and improved README documentation
1 parent 744a317 commit a8da1ef

7 files changed

Lines changed: 80 additions & 52 deletions

File tree

exercises/03.inheritance-and-polymorphism/02.problem.method-overriding/README.mdx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,13 @@
33
👨‍💼 Now let's add methods to our shape hierarchy. Each shape will override a
44
method to provide its own implementation.
55

6+
The `Shape`, `Circle`, and `Rectangle` classes from the previous exercise are
7+
already defined. You'll add and override the `getArea()` method.
8+
69
🐨 Open <InlineFile file="index.ts" /> and:
710

811
1. Add a `getArea()` method to `Shape` that returns 0
912
2. Override `getArea()` in `Circle` to return π × radius²
1013
3. Override `getArea()` in `Rectangle` to return width × height
11-
4. Optionally use `super` to call the parent method
1214

1315
📜 [TypeScript Handbook - Overriding Methods](https://www.typescriptlang.org/docs/handbook/2/classes.html#overriding-methods)
Lines changed: 33 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,43 @@
11
// Method Overriding
22

3-
// 🐨 Create a Shape base class with:
4-
// - Field: color (string)
5-
// - Constructor that takes color
6-
// - Method: getArea() returns 0
3+
class Shape {
4+
color: string
75

8-
// 🐨 Create a Circle class that extends Shape:
9-
// - Field: radius (number)
10-
// - Constructor that takes color and radius
11-
// - Override getArea() to return Math.PI * radius ** 2
6+
constructor(color: string) {
7+
this.color = color
8+
}
129

13-
// Test Circle
14-
// const circle = new Circle('red', 5)
15-
// console.log(circle.getArea()) // Should print ~78.54
16-
// console.log(circle)
10+
// 🐨 Add a getArea() method that returns 0
11+
}
12+
13+
class Circle extends Shape {
14+
radius: number
15+
16+
constructor(color: string, radius: number) {
17+
super(color)
18+
this.radius = radius
19+
}
20+
21+
// 🐨 Override getArea() to return Math.PI * radius ** 2
22+
}
1723

18-
// 🐨 Create a Rectangle class that extends Shape:
19-
// - Fields: width (number), height (number)
20-
// - Constructor that takes color, width, and height
21-
// - Override getArea() to return width * height
24+
class Rectangle extends Shape {
25+
width: number
26+
height: number
2227

23-
// Test Rectangle
28+
constructor(color: string, width: number, height: number) {
29+
super(color)
30+
this.width = width
31+
this.height = height
32+
}
33+
34+
// 🐨 Override getArea() to return width * height
35+
}
36+
37+
// Test getArea methods
38+
// const circle = new Circle('red', 5)
2439
// const rectangle = new Rectangle('blue', 10, 20)
40+
// console.log(circle.getArea()) // Should print ~78.54
2541
// console.log(rectangle.getArea()) // Should print 200
26-
// console.log(rectangle)
2742

2843
// export { Shape, Circle, Rectangle }

exercises/03.inheritance-and-polymorphism/03.problem.substitutability/README.mdx

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,18 @@
33
👨‍💼 Let's build a media player that can play different types of media files.
44
We'll use polymorphism to handle all media types uniformly.
55

6+
The `MediaFile`, `AudioFile`, and `VideoFile` classes are already defined.
7+
You'll create a `MediaPlayer` that works with any of them.
8+
69
🐨 Open <InlineFile file="index.ts" /> and:
710

8-
1. Create a `MediaFile` base class with a `play()` method
9-
2. Create `AudioFile` and `VideoFile` classes that extend `MediaFile`
10-
3. Each should override `play()` with its own implementation
11-
4. Create a `MediaPlayer` class with a method that accepts `MediaFile`
12-
5. Demonstrate that both `AudioFile` and `VideoFile` can be used interchangeably
11+
1. Create a `MediaPlayer` class with a `playFile()` method
12+
2. The method should accept a `MediaFile` parameter
13+
3. Call `media.play()` and return the result
14+
4. Test it with both `AudioFile` and `VideoFile` instances
15+
16+
💰 The key insight: `playFile()` accepts `MediaFile`, but it works with any
17+
subclass (`AudioFile`, `VideoFile`) because of substitutability—subclasses
18+
can be used wherever their parent class is expected.
1319

1420
📜 [TypeScript Handbook - Classes](https://www.typescriptlang.org/docs/handbook/2/classes.html)
Lines changed: 25 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,38 @@
11
// Substitutability - Polymorphism
22

3-
// 🐨 Create a MediaFile base class with:
4-
// - Field: filename (string)
5-
// - Constructor that takes filename
6-
// - Method: play() returns string "Playing {filename}"
7-
8-
// 🐨 Create an AudioFile class that extends MediaFile:
9-
// - Override play() to return "Playing audio: {filename}"
10-
11-
// Test AudioFile
12-
// const audio = new AudioFile('song.mp3')
13-
// console.log(audio)
14-
15-
// 🐨 Create a VideoFile class that extends MediaFile:
16-
// - Override play() to return "Playing video: {filename}"
17-
18-
// Test VideoFile
19-
// const video = new VideoFile('movie.mp4')
20-
// console.log(video)
3+
class MediaFile {
4+
filename: string
5+
6+
constructor(filename: string) {
7+
this.filename = filename
8+
}
9+
10+
play(): string {
11+
return `Playing ${this.filename}`
12+
}
13+
}
14+
15+
class AudioFile extends MediaFile {
16+
play(): string {
17+
return `Playing audio: ${this.filename}`
18+
}
19+
}
20+
21+
class VideoFile extends MediaFile {
22+
play(): string {
23+
return `Playing video: ${this.filename}`
24+
}
25+
}
2126

2227
// 🐨 Create a MediaPlayer class with:
2328
// - Method: playFile(media: MediaFile) returns string
2429
// - Calls media.play() and returns the result
2530

2631
// Test MediaPlayer (polymorphism)
32+
// const audio = new AudioFile('song.mp3')
33+
// const video = new VideoFile('movie.mp4')
2734
// const player = new MediaPlayer()
2835
// console.log(player.playFile(audio)) // Should work - AudioFile is substitutable for MediaFile
2936
// console.log(player.playFile(video)) // Should work - VideoFile is substitutable for MediaFile
30-
// console.log(player)
3137

3238
// export { MediaFile, AudioFile, VideoFile, MediaPlayer }

exercises/04.composition-vs-inheritance/02.problem.dependency-injection/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ class EmailService {
2525
// - Extends Logger
2626
// - Override log() to store messages in an array: #logs (private field)
2727
// - Stores messages instead of printing them
28-
// - Method: getLogs() returns string[] to retrieve stored messages
28+
// - Method: getLogs() returns Array<string> to retrieve stored messages
2929

3030
// Test MockLogger
3131
// const mockLogger = new MockLogger()

exercises/04.composition-vs-inheritance/02.solution.dependency-injection/index.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,13 @@ class EmailService {
2121

2222
// MockLogger stores logs in memory (useful for testing)
2323
class MockLogger extends Logger {
24-
#logs: string[] = []
24+
#logs: Array<string> = []
2525

2626
log(message: string): void {
2727
this.#logs.push(message)
2828
}
2929

30-
getLogs(): string[] {
30+
getLogs(): Array<string> {
3131
return [...this.#logs] // Return a copy to prevent external mutation
3232
}
3333
}

exercises/README.mdx

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,9 @@ combine data and behavior. TypeScript makes OOP powerful with its type system.
99
We'll cover:
1010

1111
1. **Classes** - Fields, methods, constructors, private fields, and defaults
12-
2. **Interfaces and Classes** - Implementing contracts
13-
3. **Inheritance** - Extending classes and overriding methods
14-
4. **Polymorphism** - Substitutability and why it matters
15-
5. **Composition vs Inheritance** - Practical decision-making
12+
2. **Interfaces and Classes** - Implementing contracts and programming to abstractions
13+
3. **Inheritance and Polymorphism** - Extending classes, overriding methods, and substitutability
14+
4. **Composition vs Inheritance** - Dependency injection and practical decision-making
1615

1716
## OOP vs Functional Programming
1817

@@ -24,7 +23,7 @@ should know the alternative:
2423

2524
```ts
2625
class ShoppingCart {
27-
#items: Product[] = []
26+
#items: Array<Product> = []
2827
addItem(product: Product) {
2928
this.#items.push(product)
3029
}
@@ -37,7 +36,7 @@ class ShoppingCart {
3736
**FP organizes around functions** - data and transformations separate:
3837

3938
```ts
40-
type Cart = readonly Product[]
39+
type Cart = ReadonlyArray<Product>
4140
const addItem = (cart: Cart, product: Product): Cart => [...cart, product]
4241
const getTotal = (cart: Cart): number =>
4342
cart.reduce((sum, p) => sum + p.price, 0)

0 commit comments

Comments
 (0)