객체지향 설계 원리 핵심정리
정보 은닉·캡슐화·상속·다형성의 차이와 객체지향 설계 원칙을 문항의 표현에 맞춰 구분합니다.
정보 은닉과 캡슐화
정보 은닉은 객체 내부의 구현이나 상태를 외부에서 직접 보지 못하게 접근 범위를 제한하는 설계 원칙입니다. 캡슐화는 데이터와 그 데이터를 다루는 연산을 하나의 객체로 묶는 구조이며, 접근 지정자와 공개 인터페이스를 통해 정보 은닉을 구현할 수 있습니다.
- 지문이 내부 속성·오퍼레이션의 외부 접근 제한을 직접 묻는다면 정보 은닉이 핵심이다.
- 캡슐화는 데이터와 연산을 하나의 단위로 묶는다는 표현에 초점을 둔다.
- 공개 인터페이스는 유지하면서 내부 구현을 바꾸면 변경 영향이 줄어든다.
상속과 다형성
상속은 기존 타입의 특성을 새 타입이 이어받아 확장하는 관계이고, 다형성은 같은 인터페이스의 호출이 실제 객체에 따라 다른 동작을 수행하는 성질입니다. 코드 문제에서는 참조 변수의 선언형과 실제 객체형을 분리해 판단합니다.
- 오버라이딩된 인스턴스 메서드는 실제 객체형에 따라 선택된다.
- 오버로딩은 같은 이름의 메서드를 매개변수 목록으로 구분한다.
- 상속을 단순 코드 복사와 같은 의미로 보지 않는다.
SOLID 5원칙과 판별 기준
SOLID는 클래스 수를 늘리는 규칙이 아니라 변경 이유, 확장 방식, 하위 타입의 계약, 인터페이스의 사용 주체, 의존 방향을 점검하는 다섯 원칙입니다. 지문에서 무엇이 바뀔 때 어느 코드까지 함께 수정되는지를 표시하면 원칙 이름을 외우는 것보다 정확하게 판별할 수 있습니다.
- SRP(단일 책임): 한 모듈은 하나의 액터·변경 이유에 책임져야 한다. 계산·DB 저장·화면 출력이 서로 다른 이유로 바뀌는데 한 클래스에 묶여 있으면 대표 위반이다.
- OCP(개방-폐쇄): 새 기능은 기존 안정 코드의 반복 수정보다 확장으로 추가할 수 있어야 한다. 유형을 추가할 때마다 기존 switch 문을 고치는 구조가 대표 위반이다.
- LSP(리스코프 치환): 하위 타입은 상위 타입의 계약을 깨지 않고 대체되어야 한다. 하위 타입이 정상 동작을 막거나 더 강한 선행조건을 요구하고 예외를 던지면 위반 가능성이 크다.
- ISP(인터페이스 분리): 클라이언트가 사용하지 않는 메서드에 의존하지 않도록 역할별 인터페이스를 나눈다. 구현 클래스가 불필요한 메서드를 빈 구현하거나 지원하지 않는 예외로 처리하면 대표 위반이다.
- DIP(의존 역전): 상위 정책과 하위 구현 모두 추상화에 의존하고 추상화는 세부사항에 끌려가지 않아야 한다. 핵심 서비스가 구체 DB·전송 클래스를 직접 생성하면 대표 위반이다.
SOLID를 서로 구분하는 출제 포인트
SRP와 ISP는 모두 작게 나누지만 SRP는 모듈의 변경 이유, ISP는 인터페이스를 사용하는 클라이언트의 필요 기능을 봅니다. OCP는 확장 시 기존 코드를 덜 고치는 결과에, DIP는 그 결과를 돕는 의존 방향에 초점이 있습니다. LSP는 상속을 썼다는 사실이 아니라 실제로 대체 가능한 계약인지를 묻습니다.
- SRP: '누가 이 코드를 변경하게 만드는가'를 묻고, 단순히 메서드 수가 많다는 이유만으로 위반이라 단정하지 않는다.
- OCP: 분기문 자체가 항상 위반은 아니지만 새 유형마다 검증된 핵심 로직을 계속 수정한다면 확장 지점이 부족하다.
- LSP: 하위 타입이 상위 타입보다 선행조건을 강화하거나 보장하던 사후조건을 약화하면 대체 가능성이 깨진다.
- ISP: 인터페이스의 절대적인 크기보다 각 클라이언트가 쓰지 않는 기능에 강제로 의존하는지를 본다.
- DIP와 의존성 주입(DI)은 같은 말이 아니다. DIP는 설계 원칙이고 DI는 의존 객체를 외부에서 제공해 이를 구현할 수 있는 방법 중 하나다.
변경 이유와 의존 방향으로 설계를 평가하기
객체지향 설계 문항은 클래스가 몇 가지 이유로 바뀌는지, 상위 정책이 구체 구현에 직접 의존하는지, 하위 타입이 상위 타입 자리에 안전하게 들어갈 수 있는지를 확인합니다. 상속은 단순 코드 재사용보다 대체 가능성이 있을 때 선택해야 합니다.
- SRP는 클래스 크기가 아니라 변경 이유의 개수에 관한 원칙이다.
- DIP는 추상화가 세부 구현에 의존하지 않고 세부 구현이 추상화에 의존하게 한다.
- 다형성은 같은 메시지에 객체별 다른 구현이 응답하도록 만든다.
SOLID 위반을 코드 구조에서 찾기
SOLID는 설명 문장에 원칙 이름이 없어도 변경 지점과 계약을 따라 판별할 수 있어야 합니다. SRP는 변경 이유, OCP는 새 유형 추가 시 수정 범위, LSP는 상위 계약 유지, ISP는 클라이언트별 필요 기능, DIP는 정책과 세부 구현의 의존 방향을 각각 확인합니다.
- SRP 위반: 보고서 계산 규칙, 파일 저장 형식, 화면 출력이 서로 다른 이유로 바뀌는데 하나의 클래스가 모두 담당한다.
- OCP 위반: 새 결제·도형·전송 유형을 넣을 때마다 여러 기존 switch 문을 찾아 수정해야 한다.
- LSP 위반: 읽기 가능한 상위 타입을 상속한 하위 타입이 정상 메서드를 지원하지 않는다며 예외를 던지거나 결과 계약을 약화한다.
- ISP 위반: 읽기 전용 클라이언트가 쓰기·삭제 메서드까지 가진 큰 인터페이스를 구현하고 사용하지 않는 메서드를 비워 둔다.
- DIP 위반: 상위 업무 정책이 구체 데이터베이스나 메시지 전송 클래스를 직접 생성해 구현 교체가 정책 코드 수정으로 이어진다.
객체 관계·GRASP·합성 판단
클래스 관계는 전체와 부분의 생명주기, 소유권, 사용 기간을 기준으로 구분합니다. 책임 할당은 필요한 정보를 가진 객체에 책임을 두고 결합도를 낮추되, 단순 재사용을 위해 부자연스러운 상속 계층을 만들지 않습니다.
- 연관은 지속적인 구조 관계, 의존은 매개변수·지역변수처럼 일시적 사용, 집합은 약한 전체-부분, 합성은 생명주기를 공유하는 강한 전체-부분 관계다.
- Information Expert는 책임 수행에 필요한 정보를 가진 객체에 책임을 배정하고 Creator는 포함·기록·긴밀 사용 관계를 생성 책임 판단에 활용한다.
- Controller는 시스템 이벤트를 받는 객체에 흐름 조정을 맡기되 모든 업무 로직을 한 컨트롤러에 몰아넣지 않는다.
- 상속은 is-a와 대체 가능성이 있을 때 사용하고, 기능 조합·교체가 목적이면 객체 합성을 우선 검토한다.
- Law of Demeter는 객체가 직접 아는 협력자와만 통신하도록 해 긴 메서드 호출 사슬과 구조 노출을 줄인다.
시험에 바로 쓰는 비교표
| 원칙 | 판별 질문 | 대표 위반 | 헷갈리는 구분 |
|---|---|---|---|
| SRP | 변경 이유가 하나인가 | 서로 다른 액터의 업무를 한 클래스가 담당 | ISP는 인터페이스 사용자 기준 |
| OCP | 새 유형을 확장으로 추가하는가 | 유형마다 기존 분기 로직 수정 | DIP는 의존 방향 기준 |
| LSP | 하위 타입이 계약을 보존하는가 | 지원하지 않는 동작·강화된 선행조건 | 단순 상속·코드 재사용과 다름 |
| ISP | 클라이언트가 쓰는 기능에만 의존하는가 | 불필요한 메서드의 빈 구현 | SRP는 변경 이유 기준 |
| DIP | 정책과 구현이 추상화에 의존하는가 | 상위 모듈이 구체 구현을 직접 생성 | DI는 구현 기법 중 하나 |
지문 표현을 판단 기준으로 바꾸기
- 내부 속성과 오퍼레이션의 외부 접근 제한 → 정보 은닉
- 데이터와 관련 연산을 하나로 묶음 → 캡슐화
- 실제 객체에 따라 재정의 메서드 실행 → 다형성
- 새 유형마다 기존 조건문을 수정 → OCP 위반 검토
- 하위 타입이 지원하지 않는 예외를 던짐 → LSP 위반 검토
- 사용하지 않는 메서드를 강제로 구현 → ISP 위반 검토
- 상위 정책이 구체 구현을 직접 생성 → DIP 위반 검토
자주 틀리는 판단
- 정보 은닉과 캡슐화를 모든 문장에서 같은 답으로 처리
- 상속과 다형성의 역할을 혼동
- 구현 클래스에 직접 의존하면서 결합도가 낮다고 판단
개념을 확인했다면 실제 문제에서 판단 기준을 적용해보세요.
분야별 문제 풀기