Skip to content
Grok

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

  1. 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) {/* ... */}
}
  1. 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());
  }
}
  1. 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!";
  }
}
  1. 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()
}
  1. 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 ขนาดใหญ่