SOLID 실전 가이드

SOLID의 핵심 개념과 실무 활용

TypeScript중급
6시간
3개 항목
학습 진행률0 / 3 (0%)

학습 항목

1. TypeScript
초급
SOLID|원칙|실무|활용|완벽|가이드
퀴즈튜토리얼
2. TypeScript
초급
SOLID|원칙|실전|프로젝트|완벽|가이드
퀴즈튜토리얼
3. TypeScript
고급
SOLID|트러블슈팅|실전|가이드
퀴즈튜토리얼
1 / 3

이미지 로딩 중...

SOLID 원칙 실무 활용 완벽 가이드 - 슬라이드 1/11

SOLID 원칙 실무 활용 완벽 가이드

객체지향 설계의 5대 원칙인 SOLID를 실무에서 바로 적용할 수 있는 실용적인 예제로 배워봅니다. 초급 개발자도 쉽게 이해하고 활용할 수 있도록 구성했습니다.


카테고리:TypeScript
언어:TypeScript
난이도:beginner
메인 태그:#TypeScript
서브 태그:
#SOLID#OOP#DesignPatterns#CleanCode

들어가며

이 글에서는 SOLID 원칙 실무 활용 완벽 가이드에 대해 상세히 알아보겠습니다. 총 10가지 주요 개념을 다루며, 각각의 개념에 대한 설명과 실제 코드 예제를 함께 제공합니다.

목차

  1. 단일_책임_원칙_SRP
  2. 개방_폐쇄_원칙_OCP
  3. 리스코프_치환_원칙_LSP
  4. 인터페이스_분리_원칙_ISP
  5. 의존성_역전_원칙_DIP
  6. SRP_실무_예제_로깅
  7. OCP_실무_예제_알림
  8. DIP_실무_예제_캐시
  9. SOLID_종합_예제_1
  10. SOLID_종합_예제_2

1. 단일_책임_원칙_SRP

개요

하나의 클래스는 하나의 책임만 가져야 합니다. 사용자 관리 클래스를 책임별로 분리하는 예제입니다.

코드 예제

// Bad: 여러 책임을 가진 클래스
class UserService {
  saveUser(user: User) { /* DB 저장 */ }
  sendEmail(user: User) { /* 이메일 전송 */ }
}

// Good: 책임을 분리
class UserRepository {
  saveUser(user: User) { /* DB 저장만 담당 */ }
}
class EmailService {
  sendEmail(user: User) { /* 이메일만 담당 */ }
}

설명

각 클래스가 하나의 책임만 가지므로 변경 사유가 명확해지고 유지보수가 쉬워집니다.


2. 개방_폐쇄_원칙_OCP

개요

확장에는 열려있고 수정에는 닫혀있어야 합니다. 새로운 기능 추가시 기존 코드를 수정하지 않는 방법입니다.

코드 예제

interface PaymentMethod {
  pay(amount: number): void;
}

class CreditCard implements PaymentMethod {
  pay(amount: number) { console.log(`카드 결제: ${amount}`); }
}

class KakaoPay implements PaymentMethod {
  pay(amount: number) { console.log(`카카오페이: ${amount}`); }
}

class Payment {
  process(method: PaymentMethod, amount: number) {
    method.pay(amount);
  }
}

설명

새로운 결제 수단을 추가할 때 Payment 클래스를 수정하지 않고 인터페이스만 구현하면 됩니다.


3. 리스코프_치환_원칙_LSP

개요

자식 클래스는 부모 클래스를 완전히 대체할 수 있어야 합니다. 직사각형과 정사각형 예제로 알아봅니다.

코드 예제

abstract class Shape {
  abstract getArea(): number;
}

class Rectangle extends Shape {
  constructor(private width: number, private height: number) {
    super();
  }
  getArea(): number { return this.width * this.height; }
}

class Square extends Shape {
  constructor(private side: number) {
    super();
  }
  getArea(): number { return this.side * this.side; }
}

설명

정사각형을 직사각형의 자식으로 만들지 않고 독립된 클래스로 설계하여 치환 원칙을 지킵니다.


4. 인터페이스_분리_원칙_ISP

개요

클라이언트는 자신이 사용하지 않는 메서드에 의존하지 않아야 합니다. 인터페이스를 작게 분리합니다.

코드 예제

// Bad: 큰 인터페이스
interface Worker {
  work(): void;
  eat(): void;
}

// Good: 분리된 인터페이스
interface Workable {
  work(): void;
}
interface Eatable {
  eat(): void;
}

class Human implements Workable, Eatable {
  work() { console.log("작업중"); }
  eat() { console.log("식사중"); }
}

설명

필요한 인터페이스만 구현하므로 불필요한 의존성이 없어지고 유연성이 높아집니다.


5. 의존성_역전_원칙_DIP

개요

구체적인 클래스가 아닌 추상화에 의존해야 합니다. 데이터베이스 연결 예제입니다.

코드 예제

interface Database {
  connect(): void;
  query(sql: string): any;
}

class MySQL implements Database {
  connect() { console.log("MySQL 연결"); }
  query(sql: string) { return "MySQL 결과"; }
}

class UserService {
  constructor(private db: Database) {}
  getUsers() {
    this.db.connect();
    return this.db.query("SELECT * FROM users");
  }
}

설명

UserService는 구체적인 MySQL이 아닌 Database 인터페이스에 의존하므로 DB 변경이 쉽습니다.


6. SRP_실무_예제_로깅

개요

로깅 기능을 별도 클래스로 분리하여 단일 책임 원칙을 적용한 실무 예제입니다.

코드 예제

class Logger {
  log(message: string) {
    console.log(`[${new Date().toISOString()}] ${message}`);
  }
}

class OrderService {
  constructor(private logger: Logger) {}

  createOrder(order: Order) {
    // 주문 생성 로직
    this.logger.log(`주문 생성: ${order.id}`);
    return order;
  }
}

설명

로깅 책임을 Logger 클래스로 분리하여 OrderService는 비즈니스 로직에만 집중합니다.


7. OCP_실무_예제_알림

개요

다양한 알림 채널을 확장 가능하게 설계한 개방-폐쇄 원칙 예제입니다.

코드 예제

interface Notifier {
  send(message: string): void;
}

class EmailNotifier implements Notifier {
  send(msg: string) { console.log(`Email: ${msg}`); }
}

class SlackNotifier implements Notifier {
  send(msg: string) { console.log(`Slack: ${msg}`); }
}

class NotificationService {
  notify(notifiers: Notifier[], msg: string) {
    notifiers.forEach(n => n.send(msg));
  }
}

설명

새로운 알림 채널 추가시 기존 코드를 수정하지 않고 Notifier 인터페이스만 구현합니다.


8. DIP_실무_예제_캐시

개요

캐시 구현체를 추상화하여 의존성을 역전시킨 실무 예제입니다.

코드 예제

interface Cache {
  get(key: string): any;
  set(key: string, value: any): void;
}

class RedisCache implements Cache {
  get(key: string) { return "Redis 데이터"; }
  set(key: string, value: any) { /* Redis 저장 */ }
}

class ProductService {
  constructor(private cache: Cache) {}

  getProduct(id: string) {
    return this.cache.get(`product:${id}`);
  }
}

설명

ProductService는 Redis가 아닌 Cache 인터페이스에 의존하여 캐시 구현체 변경이 자유롭습니다.


9. SOLID_종합_예제_1

개요

여러 SOLID 원칙을 함께 적용한 사용자 인증 시스템 예제입니다.

코드 예제

interface AuthStrategy {
  authenticate(credentials: any): boolean;
}

class JWTAuth implements AuthStrategy {
  authenticate(token: string) {
    return token.length > 0;
  }
}

class AuthService {
  constructor(private strategy: AuthStrategy) {}

  login(credentials: any): boolean {
    return this.strategy.authenticate(credentials);
  }
}

설명

OCP와 DIP를 활용하여 다양한 인증 방식을 쉽게 교체하고 확장할 수 있습니다.


10. SOLID_종합_예제_2

개요

파일 처리 시스템에 SOLID 원칙을 적용한 종합 예제입니다.

코드 예제

interface FileReader {
  read(path: string): string;
}

interface FileWriter {
  write(path: string, content: string): void;
}

class TextFileReader implements FileReader {
  read(path: string) { return "파일 내용"; }
}

class FileProcessor {
  constructor(
    private reader: FileReader,
    private writer: FileWriter
  ) {}
}

설명

ISP로 읽기/쓰기를 분리하고 DIP로 구체적 구현에 의존하지 않아 테스트와 확장이 쉽습니다.


마치며

이번 글에서는 SOLID 원칙 실무 활용 완벽 가이드에 대해 알아보았습니다. 총 10가지 개념을 다루었으며, 각각의 사용법과 예제를 살펴보았습니다.

관련 태그

#TypeScript #SOLID #OOP #DesignPatterns #CleanCode

#TypeScript#SOLID#OOP#DesignPatterns#CleanCode