Dark mode
Object-Oriented Programming (OOP)
แนวคิดหลัก
Encapsulation: การห่อหุ้มข้อมูลและเมธอดที่เกี่ยวข้องไว้ในคลาสเดียวกัน และควบคุมการเข้าถึงผ่าน access modifiers
ts
class BankAccount {
private balance: number;
constructor(initialBalance: number) {
this.balance = initialBalance;
}
// Public method to access private data
public deposit(amount: number): void {
if (amount > 0) {
this.balance += amount;
}
}
public getBalance(): number {
return this.balance;
}
}
const account = new BankAccount(1000);
account.deposit(500);
console.log(account.getBalance()); // 1500
Inheritance: การสืบทอดคุณสมบัติจากคลาสแม่ไปยังคลาสลูก
ts
// Base class
class Animal {
constructor(public name: string) {}
makeSound(): string {
return "Some sound";
}
}
// Derived class
class Dog extends Animal {
constructor(name: string, public breed: string) {
super(name);
}
// Method overriding
makeSound(): string {
return "Woof!";
}
// New method specific to Dog
fetch(item: string): string {
return `${this.name} fetches the ${item}`;
}
}
const myDog = new Dog("Buddy", "Golden Retriever");
console.log(myDog.makeSound()); // "Woof!"
console.log(myDog.fetch("ball")); // "Buddy fetches the ball"
Polymorphism: ความสามารถของอ็อบเจ็กต์ในการตอบสนองต่อเมธอดเดียวกันในรูปแบบที่ต่างกัน
ts
class Shape {
area(): number {
return 0;
}
}
class Circle extends Shape {
constructor(private radius: number) {
super();
}
area(): number {
return Math.PI * this.radius * this.radius;
}
}
class Rectangle extends Shape {
constructor(private width: number, private height: number) {
super();
}
area(): number {
return this.width * this.height;
}
}
// Function that works with any Shape
function printArea(shape: Shape): void {
console.log(`Area: ${shape.area().toFixed(2)}`);
}
const circle = new Circle(5);
const rectangle = new Rectangle(4, 6);
printArea(circle); // Area: 78.54
printArea(rectangle); // Area: 24.00
Abstraction: การซ่อนรายละเอียดการทำงานที่ซับซ้อนและแสดงเฉพาะส่วนที่จำเป็น
ts
// Abstract class
abstract class Vehicle {
constructor(public make: string, public model: string) {}
// Abstract method (no implementation)
abstract startEngine(): string;
// Concrete method
getInfo(): string {
return `${this.make} ${this.model}`;
}
}
class Car extends Vehicle {
startEngine(): string {
return `${this.getInfo()} engine started with a key`;
}
}
class ElectricCar extends Vehicle {
startEngine(): string {
return `${this.getInfo()} engine started with a button`;
}
}
const myCar = new Car("Toyota", "Camry");
const myEV = new ElectricCar("Tesla", "Model 3");
console.log(myCar.startEngine()); // "Toyota Camry engine started with a key"
console.log(myEV.startEngine()); // "Tesla Model 3 engine started with a button"
หลักการสำคัญของ OOP
SOLID Principles
- Single Responsibility Principle (SRP): แต่ละคลาสควรมีหน้าที่เดียว
ts
// Bad
class User {
saveToDatabase() {/* ... */}
sendEmail() {/* ... */}
validate() {/* ... */}
}
// Good
class User {
validate() {/* ... */}
}
class UserRepository {
save(user: User) {/* ... */}
}
class EmailService {
sendEmail(user: User) {/* ... */}
}
- Open/Closed Principle (OCP): เปิดให้ขยายได้ แต่ปิดสำหรับการแก้ไข
ts
// Bad
class Discount {
getDiscount(type: string): number {
if (type === "premium") return 0.3;
if (type === "vip") return 0.5;
return 0.1;
}
}
// Good
interface DiscountStrategy {
getDiscount(): number;
}
class PremiumDiscount implements DiscountStrategy {
getDiscount(): number {
return 0.3;
}
}
class VipDiscount implements DiscountStrategy {
getDiscount(): number {
return 0.5;
}
}
class RegularDiscount implements DiscountStrategy {
getDiscount(): number {
return 0.1;
}
}
class DiscountManager {
constructor(private strategy: DiscountStrategy) {}
calculate(price: number): number {
return price * (1 - this.strategy.getDiscount());
}
}
- Liskov Substitution Principle (LSP): อ็อบเจ็กต์ของคลาสลูกต้องสามารถแทนที่อ็อบเจ็กต์ของคลาสแม่ได้โดยไม่ทำให้โปรแกรมผิดพลาด
ts
class Bird {
fly(): string {
return "Flying";
}
}
class Duck extends Bird {
quack(): string {
return "Quack!";
}
}
class Ostrich extends Bird {
// Ostriches can't fly, so we violate LSP if we inherit from Bird
fly(): string {
throw new Error("Ostriches cannot fly!");
}
}
// Better approach
class Bird {
makeSound(): string {
return "Some bird sound";
}
}
class FlyingBird extends Bird {
fly(): string {
return "Flying";
}
}
class Duck extends FlyingBird {
makeSound(): string {
return "Quack!";
}
}
class Ostrich extends Bird {
run(): string {
return "Running fast!";
}
}
- Interface Segregation Principle (ISP): แยก interface ออกเป็นส่วนเล็กๆ เฉพาะที่จำเป็น
ts
// Bad
interface Worker {
work(): void;
eat(): void;
sleep(): void;
}
// Good
interface Workable {
work(): void;
}
interface Eatable {
eat(): void;
}
interface Sleepable {
sleep(): void;
}
class HumanWorker implements Workable, Eatable, Sleepable {
work() {/* ... */}
eat() {/* ... */}
sleep() {/* ... */}
}
class RobotWorker implements Workable {
work() {/* ... */}
// No need to implement eat() or sleep()
}
- Dependency Inversion Principle (DIP): ขึ้นอยู่กับ abstraction ไม่ใช่ concrete implementation
ts
// Bad
class LightBulb {
turnOn() {/* ... */}
turnOff() {/* ... */}
}
class Switch {
private bulb: LightBulb;
constructor() {
this.bulb = new LightBulb();
}
operate() {/* ... */}
}
// Good
interface Switchable {
turnOn(): void;
turnOff(): void;
}
class LightBulb implements Switchable {
turnOn() {/* ... */}
turnOff() {/* ... */}
}
class Fan implements Switchable {
turnOn() {/* ... */}
turnOff() {/* ... */}
}
class Switch {
constructor(private device: Switchable) {}
operate() {
// Use the injected device
this.device.turnOn();
// ...
this.device.turnOff();
}
}
// Usage
const bulb = new LightBulb();
const bulbSwitch = new Switch(bulb);
const fan = new Fan();
const fanSwitch = new Switch(fan);
เหมาะสำหรับ
- การพัฒนาซอฟต์แวร์ขนาดใหญ่ที่ต้องการการจัดการโค้ดที่มีโครงสร้างชัดเจน
- ระบบที่ต้องการการนำโค้ดกลับมาใช้ซ้ำ (code reusability)
- โปรเจกต์ที่ต้องการการบำรุงรักษาในระยะยาว
- การทำงานเป็นทีมขนาดใหญ่ที่ต้องการแบ่งงานตามโมดูล
- ระบบที่ต้องการสร้างความสัมพันธ์ระหว่างอ็อบเจ็กต์ที่ซับซ้อน
- การพัฒนา GUI applications, games, และระบบ enterprise ขนาดใหญ่