함께 배우는 수업 · 컴퓨터/정보
객체지향 프로그래밍 (OOP)
클래스(Class)와 인스턴스(Object), 객체지향 4대 핵심 특성(캡슐화, 상속, 다형성, 추상화)과 유지보수성을 극대화하는 SOLID 5대 설계 원칙을 학습합니다.
이 수업에서 해 볼 일
- 캡슐화·상속·다형성을 구체적인 설계에서 구별한다
먼저 알면 좋은 것: 변수(상태 데이터)와 함수(행동 로직)의 기본 구조 · 메모리 힙(Heap) 영역의 객체 생성과 참조(Reference) · 모듈화와 인터페이스(Interface) 개념
오늘의 목표
가입 없이 시작할 수 있어요. 설명을 읽고, 함께 연습한 뒤, 처음 보는 문제에서 직접 확인합니다.
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의 핵심 원리).예제로 살펴보기
결제 시스템에서OrderService가 if payType == 'CARD': KakaoPay().pay() / elif payType == 'NAVER': NaverPay().pay()처럼 분기문으로 구현되어 있을 때 위반된 SOLID 원칙을 지적하고, 다형성(인터페이스)을 활용해 리팩토링하는 방법을 설명하시오.- 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)'입니다. 클래스 내부의 관련 기능은 똘똘 뭉치게(응집도↑) 만들고, 다른 클래스와의 의존성은 인터페이스를 통해 느슨하게(결합도↓) 연결하세요.참고 근거와 확인 범위
- Python 공식 문서 · Classes ↗
클래스·인스턴스·상속의 기본 개념
설명·예제·문제 구성 및 오류 수정 책임: 프리런. 위 자료는 표시한 주제를 확인하거나 더 읽기 위한 근거이며, 외부 기관의 공식 수업이나 감수본을 뜻하지 않습니다.
참고 자료 연결 점검: 2026-11-02. 제작 방식·검수 범위와 수정 기록에서 확인 범위를 볼 수 있습니다. 오류는 상단의 의견 보내기 또는 contact@freelearn.io로 알려 주세요.