객체지향 프로그래밍 (OOP)
한눈에 보기
객체지향 프로그래밍은 데이터와 동작을 묶은 객체들의 협력으로 프로그램을 구성하는 패러다임이다. 캡슐화, 상속, 다형성, 추상화의 네 가지 특성과 SOLID 원칙, 실무 적용의 한계까지 정리한다.
최종 업데이트 2026.09.17
객체지향 프로그래밍(Object-Oriented Programming, OOP)은 프로그램을 데이터와 그 데이터를 다루는 동작을 하나로 묶은 객체(Object)들의 협력으로 구성하는 프로그래밍 패러다임이다. 객체지향 프로그래밍은 캡슐화, 상속, 다형성, 추상화라는 네 가지 특성을 통해 현실의 개념을 코드로 모델링하고, 변경에 유연하며 재사용 가능한 구조를 만드는 것을 목표로 한다. 자바(Java), C++, 파이썬(Python), 코틀린(Kotlin) 등 주류 언어 대부분이 이 패러다임을 지원한다.
절차지향과 무엇이 다른가
절차지향 프로그래밍은 프로그램을 순서대로 실행되는 함수들의 흐름으로 보고, 데이터는 함수들 사이를 오가는 대상으로 다룬다. 규모가 작을 때는 단순하고 효율적이지만, 프로그램이 커지면 어떤 함수가 어떤 데이터를 언제 바꾸는지 추적하기 어려워지고, 데이터 구조가 바뀌면 그 데이터를 만지는 모든 함수를 찾아 고쳐야 하는 문제가 커진다. 객체지향은 관점을 뒤집어 데이터와 동작을 한 객체 안에 두고, 외부에는 동작(메시지)만 노출한다. 데이터의 내부 표현이 바뀌어도 그 영향이 객체 내부에 갇히므로 변경 비용이 줄어든다.
| 구분 | 절차지향 | 객체지향 |
|---|---|---|
| 구성 단위 | 함수와 데이터의 분리 | 데이터와 동작을 묶은 객체 |
| 변경 파급 | 데이터 구조 변경이 넓게 전파 | 캡슐화로 내부에 국한 |
| 재사용 | 함수 단위 재사용 | 클래스, 상속, 조합으로 재사용 |
| 적합한 영역 | 단순한 스크립트, 시스템 프로그래밍 | 도메인이 복잡한 대규모 애플리케이션 |
네 가지 특성
캡슐화(Encapsulation)
객체의 내부 상태를 숨기고 공개된 메서드로만 접근하게 하는 것이다. 핵심은 정보 은닉이 아니라 불변식(Invariant)의 보호다. 예를 들어 잔액이 음수가 될 수 없다는 규칙은, 잔액 필드를 외부에서 직접 수정할 수 없고 출금 메서드가 검증을 강제할 때만 지켜진다. 모든 필드에 기계적으로 게터와 세터를 만드는 것은 캡슐화가 아니라 캡슐화의 우회다.
상속(Inheritance)
기존 클래스의 속성과 동작을 물려받아 확장하는 것이다. 코드 재사용 수단으로 소개되지만, 본질적인 가치는 부모 타입으로 자식 객체를 다룰 수 있게 하는 타입 계층의 형성에 있다. 상속은 부모의 구현에 자식이 강하게 결합되는 비용이 있어, 재사용만이 목적이라면 다른 객체를 부품으로 품는 조합(Composition)이 권장된다. 이를 "상속보다 조합"이라고 부른다.
다형성(Polymorphism)
같은 메시지가 객체의 실제 타입에 따라 다르게 동작하는 성질이다. 호출하는 쪽은 인터페이스만 알면 되고, 어떤 구현이 실행될지는 실행 시점에 결정된다. 조건 분기 없이 새로운 타입을 추가할 수 있게 하는 객체지향 유연성의 핵심이다. 메서드 재정의(Overriding)를 통한 동적 다형성과, 같은 이름에 다른 매개변수를 허용하는 오버로딩(Overloading) 같은 정적 다형성으로 나뉜다.
추상화(Abstraction)
대상의 본질적인 특징만 남기고 불필요한 세부 사항을 감추는 것이다. 인터페이스(Interface)나 추상 클래스로 "무엇을 하는가"를 정의하고 "어떻게 하는가"는 구현체에 맡긴다.
interface Notifier {
void send(String message);
}
class EmailNotifier implements Notifier {
public void send(String message) { /* 이메일 발송 */ }
}
class SlackNotifier implements Notifier {
public void send(String message) { /* 슬랙 발송 */ }
}
class OrderService {
private final Notifier notifier;
OrderService(Notifier notifier) { // 구현이 아닌 추상에 의존한다
this.notifier = notifier;
}
void complete(Order order) {
// 주문 처리 로직
notifier.send("주문이 완료되었습니다");
}
}
OrderService는 알림 수단이 무엇인지 모른 채 동작하며, 새 알림 채널이 생겨도 이 클래스는 수정할 필요가 없다. 다형성과 추상화, 그리고 의존성 주입(Dependency Injection)이 결합된 전형적인 형태다.
네 가지 특성을 각각 외우는 것보다 중요한 것은 이들이 향하는 하나의 관점이다. 객체지향의 창시자 앨런 케이(Alan Kay)는 객체지향의 본질이 클래스가 아니라 메시징(Messaging)이라고 강조했다. 좋은 객체지향 코드는 객체에게 데이터를 꺼내 달라고 묻고 밖에서 판단하는 대신, 일을 해 달라고 시킨다. 이를 "묻지 말고 시켜라(Tell, Don't Ask)" 원칙이라고 부르며, 게터로 상태를 꺼내 외부에서 조건 분기하는 코드가 늘어난다면 책임이 잘못된 곳에 있다는 신호다.
SOLID 원칙
객체지향 설계의 품질 기준으로 널리 쓰이는 다섯 원칙이다.
- 단일 책임 원칙(Single Responsibility Principle): 클래스는 변경의 이유를 하나만 가져야 한다.
- 개방 폐쇄 원칙(Open-Closed Principle): 확장에는 열려 있고 수정에는 닫혀 있어야 한다. 새 기능을 기존 코드 수정 없이 새 클래스 추가로 해결할 수 있는 구조를 지향한다.
- 리스코프 치환 원칙(Liskov Substitution Principle): 자식 타입은 부모 타입이 쓰이는 자리에서 프로그램의 정확성을 깨지 않고 대체될 수 있어야 한다. 이 원칙이 깨지는 상속은 잘못된 상속이다.
- 인터페이스 분리 원칙(Interface Segregation Principle): 클라이언트가 사용하지 않는 메서드에 의존하지 않도록 인터페이스를 작게 나눈다.
- 의존성 역전 원칙(Dependency Inversion Principle): 고수준 모듈이 저수준 구현이 아니라 추상에 의존하게 한다.
실무 적용과 한계
객체지향의 실무 가치는 문법이 아니라 변경 비용의 관리에 있다. 요구사항이 바뀌었을 때 수정 범위가 좁게 갇히는 구조가 좋은 객체지향 설계다. 다만 과도한 추상화는 역효과를 낸다. 구현체가 하나뿐인 인터페이스를 습관적으로 만들거나, 깊은 상속 계층으로 코드 흐름을 추적하기 어렵게 만드는 것이 대표적이다. 또한 도메인 로직이 객체에 담기지 않고 데이터만 담은 클래스와 로직만 담은 서비스로 분리되는 빈약한 도메인 모델(Anemic Domain Model)은 객체지향의 형태만 남긴 절차지향이라는 비판을 받는다. 현대 실무에서는 큰 구조는 객체지향으로 잡고 데이터 변환은 함수형 스타일로 쓰는 혼합이 일반적이며, 패러다임 자체보다 낮은 결합도와 높은 응집도라는 목표가 본질이다.
면접에서 이렇게 물어본다
- 객체지향의 네 가지 특성을 실제 코드 사례와 함께 설명해 보라.
- 캡슐화가 단순히 필드를 private으로 만드는 것과 어떻게 다른지 설명해 보라.
- 상속보다 조합을 권장하는 이유는 무엇인가.
- SOLID 원칙 중 하나를 골라 위반 사례와 개선 방법을 설명해 보라.
- 오버로딩과 오버라이딩의 차이를 다형성 관점에서 설명해 보라.
소프트웨어 공학에서 같이 읽기
- 애자일 (Agile)애자일은 2001년 애자일 소프트웨어 개발 선언에 뿌리를 둔 개발 철학으로, 계획과 문서보다 동작하는 소프트웨어와 협력을 앞세운다. 네 가지 가치와 열두 원칙, 폭포수 모델과의 차이, 흔한 오해까지 정리한다.
- 애자일 방법론: 스크럼과 칸반 (Scrum and Kanban)애자일 철학을 실천하는 대표 방법론인 스크럼과 칸반을 다룬다. 스크럼의 역할, 이벤트, 산출물과 칸반의 WIP 제한, 두 방식의 비교와 실무 적용 시 주의점을 정리한다.
- 클린 코드와 리팩토링 (Clean Code and Refactoring)클린 코드는 읽고 수정하기 쉬운 코드, 리팩토링은 동작을 바꾸지 않고 구조를 개선하는 활동이다. 코드 스멜, 대표 리팩토링 기법, 테스트 안전망을 갖춘 안전한 절차와 판단 기준을 정리한다.
- 클린 코드와 시큐어 코딩 (Secure Coding)시큐어 코딩은 구현 단계부터 보안 취약점을 막는 방법론이다. 모든 입력을 신뢰하지 않는다는 원칙, SQL 삽입과 XSS 방어, OWASP 기준 취약점 대응과 클린 코드가 보안을 돕는 이유를 정리한다.
이 개념, 내 코드에서는 어떻게 물어볼까요
데브핏(DevFit)에 채용공고 URL을 붙여 넣고 레포지토리를 연결하면, 내가 쓴 커밋에서 예상 질문과 어필 포인트를 만듭니다. 하루 10회까지 무료입니다. 합불 판정이나 지원자 랭킹은 만들지 않고, 최종 판단은 사람이 합니다.
공고 넣고 시작하기