-
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가지 원칙이며, 각각 [단일 책임], [확장 개방&변경 폐쇄], [리스코프 치환 원칙 - 하위클라스 가능] , [인터페이스 분리- 필요한 인터페이스만 사용 ] 그리고 [의존성 주입]이 있음
'> 기초 > 백그라운드' 카테고리의 다른 글
TIL-2024.04.18 - Basic - Origin & Site (보험) (0) 2024.04.18 TIL-2024.04.17 - Basic - JWT - 1.5 - Token, XSS & CSRF (Refresh Token & Access Token 저장 위치) (0) 2024.04.17 TIL-2024.04.16 - Basic - JWT (JSON Web Token) (0) 2024.04.16 TIL-2024.04.12 - Basic - OOP. 객체지향프로그래밍(OOP) (0) 2024.04.12 TIL-2024.04.01 - Network - TCP & UDP (0) 2024.04.01