CS/Algorithm

📌 객체지향 프로그래밍(OOP), SOLID 원칙, 디자인 패턴, DI - TypeScript 예제 포함 상세 설명

nkm 2025. 2. 2. 20:23
728x90
반응형

1. 객체지향 프로그래밍 (OOP)

객체(Object)를 중심으로 설계하는 프로그래밍 패러다임으로, 캡슐화, 상속, 다형성, 추상화를 기반으로 함.

1.1 OOP의 4대 원칙

원칙 설명 TypeScript 적용
캡슐화 (Encapsulation) 데이터를 외부에서 직접 접근하지 못하게 하고, 메서드를 통해 조작 private 또는 protected 키워드 사용
상속 (Inheritance) 부모 클래스의 속성과 메서드를 자식 클래스가 재사용 extends 키워드 사용
다형성 (Polymorphism) 같은 인터페이스/부모 클래스를 공유하는 객체들이 서로 다른 동작을 할 수 있도록 함 interface 또는 abstract class 활용
추상화 (Abstraction) 불필요한 세부사항을 숨기고, 중요한 부분만 노출 abstract class 사용

🔹 TypeScript 예제 (OOP 적용)

// ✅ 1️⃣ 캡슐화: private 사용
class User {
  private password: string;

  constructor(public username: string, password: string) {
    this.password = password;
  }

  authenticate(inputPassword: string): boolean {
    return this.password === inputPassword;
  }
}

// ✅ 2️⃣ 상속: extends 사용
class Admin extends User {
  constructor(username: string, password: string, public role: string) {
    super(username, password);
  }
}

// ✅ 3️⃣ 다형성: interface 사용
interface Animal {
  makeSound(): void;
}

class Dog implements Animal {
  makeSound() {
    console.log("멍멍!");
  }
}

class Cat implements Animal {
  makeSound() {
    console.log("야옹!");
  }
}

// ✅ 4️⃣ 추상화: abstract class 사용
abstract class Vehicle {
  abstract start(): void;
}

class Car extends Vehicle {
  start() {
    console.log("🚗 시동을 겁니다.");
  }
}

2. SOLID 원칙

객체지향 설계를 더욱 견고하고 유지보수하기 쉽게 만드는 5가지 원칙.

2.1 SOLID 원칙 설명 및 TypeScript 적용

✅ 2.1.1 SRP (단일 책임 원칙)

"하나의 클래스는 하나의 책임(기능)만 가져야 한다."

// ❌ 잘못된 예제 (SRP 위반)
class User {
  saveToDatabase() { /* DB 저장 로직 */ }
  sendEmail() { /* 이메일 발송 로직 */ }
}

// ✅ 올바른 예제 (SRP 적용)
class UserRepository {
  saveToDatabase() { /* DB 저장 */ }
}

class EmailService {
  sendEmail() { /* 이메일 발송 */ }
}

✅ 2.1.2 OCP (개방-폐쇄 원칙)

"기존 코드를 수정하지 않고 확장할 수 있어야 한다."

// ❌ OCP 위반: 새로운 결제 방식이 추가될 때마다 if-else를 수정해야 함.
class PaymentService {
  processPayment(type: string, amount: number) {
    if (type === "credit") {
      console.log(`💳 ${amount}원 신용카드 결제`);
    } else if (type === "paypal") {
      console.log(`💻 ${amount}원 PayPal 결제`);
    }
  }
}

// ✅ OCP 적용: 새로운 결제 방식이 추가되어도 기존 코드 수정이 필요 없음
interface PaymentStrategy {
  pay(amount: number): void;
}

class CreditCardPayment implements PaymentStrategy {
  pay(amount: number): void {
    console.log(`💳 ${amount}원 신용카드 결제`);
  }
}

class PaypalPayment implements PaymentStrategy {
  pay(amount: number): void {
    console.log(`💻 ${amount}원 PayPal 결제`);
  }
}

class Order {
  constructor(private payment: PaymentStrategy) {}

  checkout(amount: number) {
    this.payment.pay(amount);
  }
}

3. 디자인 패턴

디자인 패턴은 소프트웨어 설계에서 반복적으로 사용되는 해결책이다.

3.1 Factory 패턴

객체 생성을 담당하는 클래스를 따로 두어 생성 과정을 캡슐화

class AnimalFactory {
  static createAnimal(type: string): Animal {
    if (type === "dog") {
      return new Dog();
    } else {
      return new Cat();
    }
  }
}
const myPet = AnimalFactory.createAnimal("dog");
myPet.makeSound();

3.2 Singleton 패턴

하나의 인스턴스만 유지하는 패턴

class Singleton {
  private static instance: Singleton;
  private constructor() {}

  static getInstance(): Singleton {
    if (!Singleton.instance) {
      Singleton.instance = new Singleton();
    }
    return Singleton.instance;
  }
}

3.3 Builder 패턴

객체 생성 시 필수 매개변수와 선택적 매개변수를 유연하게 설정

class CarBuilder {
  private brand!: string;
  private model!: string;
  private color?: string;

  setBrand(brand: string): CarBuilder {
    this.brand = brand;
    return this;
  }

  setModel(model: string): CarBuilder {
    this.model = model;
    return this;
  }

  setColor(color: string): CarBuilder {
    this.color = color;
    return this;
  }

  build(): Car {
    return new Car(this.brand, this.model, this.color);
  }
}
const myCar = new CarBuilder().setBrand("Tesla").setModel("Model S").setColor("Red").build();

4. 의존성 주입 (DI - Dependency Injection)

클래스가 직접 의존성을 생성하지 않고, 외부에서 주입받도록 설계

interface Database {
  connect(): void;
}

class MySQLDatabase implements Database {
  connect(): void {
    console.log("MySQL 데이터베이스 연결됨");
  }
}

class UserService {
  constructor(private db: Database) {}

  getUser() {
    this.db.connect();
    console.log("사용자 정보 가져오기");
  }
}

const userService = new UserService(new MySQLDatabase());
userService.getUser(); // MySQL 데이터베이스 연결됨

🚀 결론

OOP → 객체지향 개념을 적용하여 코드의 재사용성과 유지보수성을 높임
SOLID 원칙 → 좋은 코드 설계를 위한 필수 원칙 적용
디자인 패턴 → Factory, Singleton, Builder 패턴 등을 활용하여 유연한 코드 작성
DI (의존성 주입) → 객체 간 결합도를 낮춰 유지보수성과 확장성을 높임

TypeScript를 활용한 객체지향 설계를 마스터하면 더 효율적인 코드 작성이 가능하다! 🚀🔥

728x90
반응형