ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • TIL-2024.04.11 - Basic - SOLID
    > 기초/백그라운드 2024. 4. 11. 20:38

     

     

     

    질문:

    1. SOLID 에 대해 알려줘 

     

     

    1. SOLID

    - 객체 지향 프로그래밍에서 소프트웨어 설계 원칙의 다섯 가지 원칙 

    - 이러한 원칙들은 소프트웨어의 유연성, 확장성, 유지 보수성을 향상시키고, 코드의 재사용성을 높이기 위해 고안

     

     

    2. 종류

     

    1. S - Single Responsibility Principle (단일 책임 원칙):

    • 한 클래스는 하나의 책임만 가져야 합니다. 이렇게 하면 클래스가 더 작고 응집력이 높아지며, 유지 보수가 용이

     

    // 예시: 주문 관리 시스템
    
    // 잘못된 설계: Order 클래스가 주문 데이터베이스 접근, 주문 유효성 검사, 주문 정보 출력 등의 다양한 책임 지님
    class Order {
      constructor() {
        this.items = [];
      }
    
      addItem(item) {
        this.items.push(item);
      }
    
      validateOrder() {
        // 주문 유효성 검사 로직
      }
    
      printOrder() {
        // 주문 정보 출력 로직
      }
    }
    
    
    
    // 올바른 설계:
    // Order 클래스는 '주문 데이터'를 저장하고, 주문 데이터의 유효성을 검사하는 등 '주문과 관련된 하나의 책임만'을 가짐. 
    // 주문 정보 출력은 Printer 클래스 등 다른 클래스에게 위임.
    class Order {
      constructor() {
        this.items = [];
      }
    
      addItem(item) {
        this.items.push(item);
      }
    }
    
    class OrderValidator {
      validateOrder(order) {
        // 주문 유효성 검사 로직
      }
    }
    
    class OrderPrinter {
      printOrder(order) {
        // 주문 정보 출력 로직
      }
    }

     

     

     

     

    2. O - Open/Closed Principle (개방-폐쇄 원칙):

    • 소프트웨어 엔티티(클래스, 모듈, 함수 등)는 확장에는 열려 있어야 하지만, 변경에는 닫혀 있어야 함
      즉, 기존의 코드를 수정하지 않고도 새로운 기능을 추가할 수 있어야 합니다.
      이를 통해 기존의 코드를 안정적으로 유지하면서 새로운 기능을 추가할 수 있습니다.
    // 예시: 도형 그리기 시스템
    
    // 잘못된 설계: 새로운 도형을 추가할 때마다 그리기 코드를 수정.
    class Shape {
      draw() {
        // 도형 그리기 로직
      }
    }
    
    // 새로운 도형 추가
    class Triangle extends Shape {
      draw() {
        // 삼각형 그리기 로직
      }
    }
    
    
    
    // 올바른 설계: 
    // 새로운 도형을 추가해도 기존의 도형 그리기 코드를 수정하지 않고도 확장할 수 있도록 도형을 추상화 
    // 각 도형에 대한 그리기 메서드를 오버라이드할 수 있도록 함.
    
    class Shape {
      draw() {
        throw new Error('이 메서드는 하위 클래스에서 오버라이드되어야 합니다.');
      }
    }
    
    class Triangle extends Shape {
      draw() {
        // 삼각형 그리기 로직
      }
    }
    
    // 새로운 도형 추가
    class Circle extends Shape {
      draw() {
        // 원 그리기 로직
      }
    }

     

     

     

     

     

    3. L - Liskov Substitution Principle (리스코프 치환 원칙):

    • 하위 타입은 상위 타입으로 대체 가능해야 합니다.
      즉, 어떤 클래스가 있을 때, 이 클래스의 하위 클래스를 사용해도 기존의 동작이 변하지 않아야 합니다.
      이는 상속을 이용할 때 서브 클래스가 기반 클래스의 대체 가능성을 보장하는 것을 의미합니다.
    // 예시: 동물의 울음 소리 시뮬레이터
    // 잘못된 설계: 각 동물 클래스는 makeSound() 메서드를 가지고 있음.
    // 그러나 개 클래스는 짖는 소리를 하지만, 고양이 클래스는 야옹 소리를 내야 함.
    class Animal {
      makeSound() {
        // 동물의 울음 소리
      }
    }
    
    class Dog extends Animal {
      makeSound() {
        console.log('멍멍');
      }
    }
    
    class Cat extends Animal {
      makeSound() {
        console.log('야옹');
      }
    }
    
    
    
    // 올바른 설계: 
    // 개와 고양이를 추상적으로 동물 클래스로 표현하고, 
    // makeSound() 메서드를 오버라이드하여 각 동물이 자신의 소리를 내도록 함.
    
    class Animal {
      makeSound() {
        throw new Error('이 메서드는 하위 클래스에서 오버라이드되어야 합니다.');
      }
    }
    
    class Dog extends Animal {
      makeSound() {
        console.log('멍멍');
      }
    }
    
    class Cat extends Animal {
      makeSound() {
        console.log('야옹');
      }
    }




    4. I - Interface Segregation Principle (인터페이스 분리 원칙):

    • 클라이언트는 자신이 사용하지 않는 인터페이스에 의존하지 않아야 합니다.
      즉, 하나의 인터페이스가 너무 많은 기능을 포함하지 않도록 분리하여 클라이언트가 필요한 기능에만 의존.
    //예시: 통신 인터페이스
    
    // 잘못된 설계: 모든 통신 인터페이스가 모든 기능을 포함하는 큰 인터페이스를 구현해야 함.
    class Communication {
      sendData(data) {
        // 데이터 전송
      }
    
      receiveData() {
        // 데이터 수신
      }
    
      displayError(error) {
        // 에러 표시
      }
    }
    
    // 올바른 설계: 
    // 클라이언트가 필요한 기능에만 의존할 수 있도록 작은 인터페이스를 여러 개 만듬
    //  클라이언트가 필요한 인터페이스만 구현하도록 함.
    
    class DataSender {
      sendData(data) {
        // 데이터 전송
      }
    }
    
    class DataReceiver {
      receiveData() {
        // 데이터 수신
      }
    }
    
    class ErrorDisplayer {
      displayError(error) {
        // 에러 표시
      }
    }

     

     

     

     

    5. D - Dependency Inversion Principle (의존 역전 원칙):

    • 고수준 모듈은 저수준 모듈에 의존해서는 안 됩니다. 둘 다 추상화에 의존
      즉, 클래스 간의 의존성은 추상화에 의존해야 하며, 구체적인 구현에 의존 X
    // 예시: 로그인 시스템
    
    
    // 잘못된 설계: 로그인 서비스가 직접 데이터베이스에 연결하여 사용자 정보를 확인함.
    class LoginService {
      constructor() {
        this.database = new Database();
      }
    
      login(username, password) {
        // 데이터베이스 연결 후 로그인 처리
      }
    }
    
    // 올바른 설계: 
    // 로그인 서비스가 데이터베이스 연결을 추상화한 인터페이스를 의존.
    // 실제 데이터베이스 연결은 인터페이스를 구현한 클래스에서 이루어지도록 함.
    
    class Database {
      connect() {
        // 데이터베이스 연결 로직
      }
    }
    
    class LoginService {
      constructor(database) {
        this.database = database;
      }
    
      login(username, password) {
        this.database.connect();
        // 로그인 처리
      }
    }

     

     

     

     

     

    답변:

    1. SOLID 란 무엇인가 ? 

    - OOP 설계에 필요한 5가지 원칙이며, 각각 [단일 책임], [확장 개방&변경 폐쇄], [리스코프 치환 원칙 - 하위클라스 가능] , [인터페이스 분리- 필요한 인터페이스만 사용 ] 그리고 [의존성 주입]이 있음

     

     

     

     

     

    댓글

Designed by Tistory.