개념 정리
객체지향 프로그래밍 (OOP)
단원 개요
클래스(Class)와 인스턴스(Object), 객체지향 4대 핵심 특성(캡슐화, 상속, 다형성, 추상화)과 유지보수성을 극대화하는 SOLID 5대 설계 원칙을 학습합니다.필수 키워드:클래스와 인스턴스클래스(Class)객체/인스턴스(Instance)메서드(Method: 행동 함수)객체지향 프로그래밍(OOP)의 4대 기둥상속 (Inheritance)추상화 (Abstraction)다형성 (Polymorphism)객체지향의 꽃SOLID 원칙
1
클래스(Class) vs 인스턴스(Object)와 OOP 4대 핵심 특성
•
클래스와 인스턴스: 클래스(Class)가 객체를 찍어내기 위한 '설계도(붕어빵 틀)'라면, 객체/인스턴스(Instance)는 그 설계도를 바탕으로 실제 힙(Heap) 메모리에 생성된 '실체(붕어빵)'입니다. 객체는 속성(Attribute/Field: 상태 데이터)과 메서드(Method: 행동 함수)를 하나로 묶어 가집니다.
•
객체지향 프로그래밍(OOP)의 4대 기둥:
1
캡슐화 (Encapsulation)와 정보 은닉: 관련된 데이터와 메서드를 하나의 캡슐(클래스)로 묶고, 외부에서 내부 데이터를 직접 조작하지 못하도록 접근 제어자(
private, protected, public)로 숨긴 뒤 공개된 메서드(Getter/Setter, 비즈니스 메서드)로만 안전하게 소통하게 합니다.2
상속 (Inheritance): 부모(Super) 클래스의 속성과 메서드를 자식(Sub) 클래스가 물려받아 코드 중복을 줄이고 계층적 분류(
is-a 관계)를 형성합니다.3
추상화 (Abstraction): 복잡한 내부 구현은 숨기고 공통적이고 핵심적인 역할(인터페이스
interface, 추상 클래스 abstract class)만을 정의하여 복잡도를 낮춥니다.4
다형성 (Polymorphism): 객체지향의 꽃으로, 하나의 인터페이스나 부모 타입 참조 변수가 실제 연결된 자식 객체의 타입에 따라 서로 다른 동작을 수행하는 능력입니다.
핵심 원리
면접 단골 비교 '오버로딩(Overloading) vs 오버라이딩(Overriding)': 오버로딩은 같은 클래스 내에서 이름은 같고 매개변수(개수/타입)가 다른 메서드를 여러 개 중복 정의하는 것이고, 오버라이딩은 부모 클래스에서 상속받은 메서드를 자식 클래스에서 자신의 역할에 맞게 덮어써서 재정의(동적 바인딩)하는 것입니다!2
객체지향 설계의 바이블: SOLID 5대 원칙
로버트 C. 마틴(Uncle Bob)이 정립한 SOLID 원칙은 시간이 지나도 변경과 확장이 쉬운 소프트웨어를 만드는 5가지 핵심 설계 지침입니다:
1
SRP (Single Responsibility Principle, 단일 책임 원칙):
•
모든 클래스는 단 하나의 책임(변경해야 할 단 하나의 이유)만 가져야 합니다. (예:
User 클래스가 DB 저장, 이메일 발송, 보고서 출력까지 다 하면 안 됨).2
OCP (Open-Closed Principle, 개방-폐쇄 원칙):
•
소프트웨어 요소는 확장(새로운 기능 추가)에는 열려(Open) 있어야 하고, 기존 코드의 수정(변경)에는 닫혀(Closed) 있어야 합니다. 다형성과 인터페이스를 통해 기존 코드를 건드리지 않고 새 클래스를 추가해 기능을 확장합니다.
3
LSP (Liskov Substitution Principle, 리스코프 치환 원칙):
•
자식 클래스는 언제나 자신의 부모 클래스 자리를 대체할 수 있어야 하며, 부모 클래스의 규약(의도된 동작)을 깨뜨려서는 안 됩니다.
4
ISP (Interface Segregation Principle, 인터페이스 분리 원칙):
•
범용적인 거대한 인터페이스 하나보다, 클라이언트의 목적에 맞게 쪼개진 여러 개의 구체적인 인터페이스가 낫습니다.
5
DIP (Dependency Inversion Principle, 의존성 역전 원칙):
•
상위 모듈이 하위 모듈의 구체적인 구현 클래스에 직접 의존하면 안 되며, 양쪽 모두 추상화(인터페이스)에 의존해야 합니다 (스프링 DI/IoC의 핵심 원리).
풀이
1) 위반된 원칙 (OCP & DIP 위반):
•
새로운 결제 수단(예:
ApplePay, TossPay)이 추가될 때마다 기존 OrderService의 if-elif 코드를 직접 열고 수정해야 하므로 개방-폐쇄 원칙(OCP)에 위배됩니다.•
또한 상위 모듈인
OrderService가 구체 클래스인 KakaoPay, NaverPay에 직접 강하게 결합되어 있어 의존성 역전 원칙(DIP)도 위반했습니다.2) 다형성을 통한 해결:
•
공통 인터페이스
PaymentGateway에 추상 메서드 pay(amount)를 정의합니다.•
KakaoPay, NaverPay, TossPay가 각각 PaymentGateway를 구현(오버라이딩)하게 합니다.•
OrderService는 오직 PaymentGateway 인터페이스만 주입받아 paymentGateway.pay(amount)를 호출하면, 향후 새 결제 수단이 100개 추가되어도 OrderService 코드는 단 한 줄도 수정할 필요가 없습니다!3
상속(is-a)보다 조합(Composition, has-a)을 선호해야 하는 이유
•
상속(Inheritance)의 단점과 강결합 문제:
•
상속은 부모 클래스의 내부 구현이 자식 클래스에 모두 노출되는 '화이트박스 재사용'이므로 캡슐화를 깨뜨리고 부모-자식 간 결합도를 극도로 높입니다. 부모 클래스의 메서드를 조금만 수정해도 이를 상속받은 수십 개의 자식 클래스가 연쇄적으로 고장 나는 '깨지기 쉬운 기반 클래스 문제(Fragile Base Class Problem)'가 발생합니다.
•
조합 (Composition -
has-a 관계):•
다른 클래스를 상속받는 대신, 필요한 기능을 가진 객체를 자신의 내부 필드(속성)로 포함(부품처럼 조립)하여 그 객체의 인터페이스 메서드를 호출해 위임(Delegation)하는 방식입니다.
•
런타임에 부품 객체를 자유롭게 교체(전략 패턴 Strategy Pattern)할 수 있어 상속보다 훨씬 유연하고 안전합니다.
학습 도움말
현대 소프트웨어 아키텍처의 제1원칙은 '높은 응집도(High Cohesion)와 낮은 결합도(Low Coupling)'입니다. 클래스 내부의 관련 기능은 똘똘 뭉치게(응집도↑) 만들고, 다른 클래스와의 의존성은 인터페이스를 통해 느슨하게(결합도↓) 연결하세요.핵심 요약
- ✓클래스는 객체의 속성과 메서드를 정의한 설계도이며, 인스턴스는 이를 바탕으로 메모리에 실체화된 객체이다.
- ✓객체지향 4대 특성은 캡슐화(정보 은닉), 상속(재사용), 추상화(공통 인터페이스 추출), 다형성(동일 인터페이스의 다양한 동작)이다.
- ✓오버로딩은 매개변수가 다른 동명 메서드의 중복 정의이고, 오버라이딩은 부모 메서드를 자식 클래스에서 재정의하는 것이다.
- ✓SOLID 원칙(특히 OCP 개방-폐쇄 원칙과 DIP 의존성 역전 원칙)은 다형성을 활용해 기존 코드 수정 없이 기능을 확장하게 해준다.