티스토리 뷰
객체지향 프로그래밍에서 '단일 책임 원칙(SRP)'과 '개방-폐쇄 원칙(OCP)'에 대해 설명하고, 각각의 원칙을 적용한 코드 예시를 들어주세요.
단일 책임 원칙(SRP : Single Responsibility Principle)이란?
하나의 클래스는 하나의 책임만 가져야 한다.
어떤 물건이 너무 많은 일(책임)을 하면 복잡해지고 관리하기가 어려워진다
'책임' 이란 클래스가 가지고 있는 역할 또는 변경이 일어나는 이유을 말함
역할 : ex) 카메라의 역할은 사진찍기 , 연필의 역할은 글쓰기, 시계의 역할은 시간알려주기 등
변경이 일어나는 이유 : ex) 사진찍기 기능이 바뀌면 카메라 클래스를 수정
왜 중요할까?
1. 유지 보수가 쉬워짐
- 단일 책임이기 때문에 로직이 섞여있지 않으므로
2. 확장(기능추가)이 쉬움
- 기존 클래스에 영향을 주지 않으므로
3. 테스트가 편해짐
- 각 클래스가 하나의 책임만 가지고 있으므로
예제
// 잘못된 예제: SRP 위반
public class Main {
public static void main(String[] args) {
PrinterAndSaver pns = new PrinterAndSaver();
pns.printAndSave("Hello World!");
}
}
class PrinterAndSaver {
// 출력과 저장을 동시에 처리 → 단일 책임 원칙 위반
public void printAndSave(String message) {
//출력
System.out.println(message);
//파일 저장
System.out.println("파일저장 : " + message);
}
}
// 정상적 예제: SRP 지킴
public class Main {
public static void main(String[] args) {
Printer printer = new Printer();
SaveFile saveFile = new SaveFile();
String txt = "Hello World!";
printer.print(txt);
saveFile.save(txt);
}
}
//프린트만 담당
class Printer {
public void print(String message) {
System.out.println(message);
}
}
//파일 저장만 담당
class SaveFile {
public void save(String message) {
System.out.println("파일저장 : " + message);
}
}
개방-폐쇄 원칙(OCP : Open–Closed Principle)란?
확장에는 열려 있어야하고, 수정에는 닫혀 있어야 한다.
기존 코드를 고치지 않고(안전한 상태) 새로운 기능을 추가(확장)할 수 있어야한다.
왜 중요할까?
1. 기존 코드 안정성 유지
- 이미 잘 동작하는 코드를 바꾸지 않음
2. 확장이 쉬움
- 기존 코드를 건들지 않기 때문
3. 유지 보수가 쉬움
- 기존 클래스 수정이 없이 확장 가능
예제
// 잘못된 예제 : OCP 위반
class Calculator {
// add나 subtract를 문자열로 구분해서 처리
public int addOrSubtract(String type, int a, int b) {
if(type.equals("add")) return a + b; // 덧셈
if(type.equals("subtract")) return a - b; // 뺄셈
return 0;
}
}
// 정상적 예제 : OCP 준수
interface Operation {
int calculate(int a, int b); // 계산 기능 정의
}
// 덧셈 클래스
class Add implements Operation {
public int calculate(int a, int b) {
return a + b; // 덧셈 처리
}
}
// 뺄셈 클래스
class Subtract implements Operation {
public int calculate(int a, int b) {
return a - b; // 뺄셈 처리
}
}
// 새로운 기능을 추가하려면,
// 기존 코드를 전혀 수정하지 않고 새 클래스만 추가하면 됨
한줄 요약
SRP : 하나의 클래스가 여러 일을 하면 복잡해지고 유지 보수가 어려우니 하나의 책임만 가지도록 만들자
OCP : 기존 코드를 건드리지 말고 새 기능은 새 클래스에 추가하자 즉, 기능 추가는 쉽게, 기존 코드는 안전하게 유지하자
----------------------------------------------------------------------------------------------------------------
Stream API의 map과 flatMap의 차이점을 설명하고, 각각의 활용 사례를 예시 코드와 함께 설명해주세요.
map의 개념
스트림의 각 요소를 다른 값으로 (1:1로)변환할 때 사용 구조는 그대로 유지된다.
왜 중요할까?
1. 데이터 변환이 간편해짐
- 리스트나 배열의 각 요소를 반복문 없이 한 줄로 변환 가능
2. 코드가 간결하고 가독성이 좋아짐
- 반복문과 조건문을 여러 줄 쓰지 않고 한줄로 처리 가능
예제
//map 사용 예제
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
public class Map {
public static void main(String[] args) {
List<String> names = Arrays.asList("Apple", "Banana", "Cherry");
// 각 이름을 대문자로 변환
List<String> upperNames = names.stream()
.map(String::toUpperCase)
.collect(Collectors.toList());
System.out.println(upperNames); // [APPLE, BANANA, CHERRY]
}
}
flatMap의 개념
스트림의 각 요소를 여러 개로 변환 후, 하나의 스트림으로 합치기
왜 중요할까?
1. 중첩된 구조를 쉽게 평탄화
-리스트 안에 리스트가 있어도 한 줄로 합칠 수 있음
2. 복잡한 데이터 처리도 간결하게 가능
- 여러 컬렉션이나 배열을 합치고 싶은 경우, 반복문 없이 처리 가능
//flatMap 예제
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
public class FlatMapExample {
public static void main(String[] args) {
List<String> words = Arrays.asList("hello", "java" ,"world");
// 각 단어를 문자 단위로 쪼개고 한 스트림으로 합치기
List<String> letters = words.stream()
.flatMap(word -> Arrays.stream(word.split("")))
.collect(Collectors.toList());
System.out.println(letters); // [h, e, l, l, o, j , a , v , a , w, o, r, l, d]
}
}
차이점
변환 방식
map : 1:1 변환
flatMap : 1:다 변환 -> 평탄화
구조
map : 컬렉션 구조 유지
flatMap : 컬렉션 구조 평탄화
사용 예시
map : 값 변환, 문자 변환 등
flatMap : 리스트 안 리스트. 문자열 쪼개기 등
한줄 요약
map : 변환만
flatMap : 변환 + 평탄화
