STUDY

[객체지향] 객체지향 4대 특성 정리: 캡슐화, 상속, 다형성, 추상화

sed 2026. 5. 29. 13:49
SMALL

객체지향 4대 특성

객체지향 프로그래밍은 프로그램을 객체들의 협력으로 바라보는 방식이다.

 

객체는 데이터와 기능을 함께 가진다.

예를 들어 회원 객체라면 이름, 이메일, 비밀번호 같은 데이터를 가질 수 있고, 로그인하기, 정보 수정하기 같은 기능을 가질 수 있다.

 

객체지향의 대표적인 4대 특성은 다음과 같다.

캡슐화
상속
다형성
추상화

 

이 네 가지는 객체지향 코드를 더 안전하고, 재사용 가능하고, 변경에 유연하게 만들기 위한 핵심 개념이다.

캡슐화

캡슐화(Encapsulation)는 객체의 데이터와 기능을 하나로 묶고, 외부에서 내부 데이터에 함부로 접근하지 못하게 제한하는 것이다.

쉽게 말하면 객체 내부의 중요한 값을 보호하는 방식이다.

 

예를 들어 은행 계좌 객체가 있다고 하자.

 

계좌에는 잔액이 있다.

Account
- balance
 

잔액은 아무렇게나 바뀌면 안 된다.
외부에서 직접 balance = -100000처럼 바꿀 수 있다면 문제가 생긴다.

 

그래서 잔액에 직접 접근하지 못하게 막고, 입금이나 출금 같은 정해진 기능을 통해서만 값을 변경하게 만든다.

class Account:
    def __init__(self):
        self.__balance = 0

    def deposit(self, money):
        if money > 0:
            self.__balance += money

    def withdraw(self, money):
        if 0 < money <= self.__balance:
            self.__balance -= money

    def get_balance(self):
        return self.__balance
 

여기서 __balance는 외부에서 직접 접근하기 어렵게 숨겨둔 값이다.

 

잔액을 바꾸려면 deposit()이나 withdraw() 같은 메서드를 사용해야 한다.

account = Account()
account.deposit(10000)
account.withdraw(3000)

print(account.get_balance())
 

이렇게 하면 잘못된 방식으로 데이터가 바뀌는 것을 막을 수 있다.

 

캡슐화의 핵심은 다음과 같다.

데이터를 외부에서 직접 건드리지 못하게 한다.
정해진 메서드를 통해서만 접근하게 한다.
객체 내부 구현을 숨긴다.
 

캡슐화를 잘하면 객체 내부 구현이 바뀌어도 외부 코드에 미치는 영향을 줄일 수 있다.

 

예를 들어 잔액을 저장하는 방식이 바뀌더라도, 외부에서는 여전히 deposit(), withdraw(), get_balance()만 사용하면 된다.

상속

상속(Inheritance)은 기존 클래스의 속성과 기능을 새로운 클래스가 물려받는 것이다.

공통 기능을 부모 클래스에 정의하고, 자식 클래스가 이를 재사용할 수 있다.

 

예를 들어 동물이라는 공통 개념이 있다고 하자.

 

개와 고양이는 모두 동물이다.

Animal
Dog
Cat
 

동물은 이름을 가질 수 있고, 소리를 낼 수 있다.

 

개와 고양이는 동물의 공통 속성을 물려받으면서 각자 다른 방식으로 소리를 낼 수 있다.

class Animal:
    def __init__(self, name):
        self.name = name

    def speak(self):
        print("동물이 소리를 냅니다.")


class Dog(Animal):
    def speak(self):
        print(f"{self.name}가 멍멍 짖습니다.")


class Cat(Animal):
    def speak(self):
        print(f"{self.name}가 야옹 웁니다.")
 

Dog와 Cat은 Animal을 상속받는다.

 

그래서 name 속성을 그대로 사용할 수 있다.

dog = Dog("초코")
cat = Cat("나비")

dog.speak()
cat.speak()
 

출력은 다음과 같다.

초코가 멍멍 짖습니다.
나비가 야옹 웁니다.
 

상속을 사용하면 공통 코드를 반복해서 작성하지 않아도 된다.

공통 기능은 부모 클래스에 둔다.
세부 기능은 자식 클래스에서 구현한다.
코드 재사용성이 높아진다.
 

다만 상속을 무조건 많이 쓰는 것이 좋은 것은 아니다.

부모 클래스와 자식 클래스의 관계가 강하게 묶이기 때문에, 부모 클래스가 바뀌면 자식 클래스에도 영향을 줄 수 있다.

 

그래서 상속은 “A는 B이다” 관계가 자연스러울 때 사용하는 것이 좋다.

Dog는 Animal이다.
Cat은 Animal이다.
 

이런 관계라면 상속이 자연스럽다.

다형성

다형성(Polymorphism)은 같은 이름의 기능이 객체에 따라 다르게 동작할 수 있는 성질이다.

조금 쉽게 말하면, 같은 메서드를 호출했는데 실제 객체에 따라 다른 결과가 나오는 것이다.

 

앞의 예시에서 Dog와 Cat은 모두 speak() 메서드를 가지고 있다.

animals = [Dog("초코"), Cat("나비")]

for animal in animals:
    animal.speak()
 

출력은 다음과 같다.

초코가 멍멍 짖습니다.
나비가 야옹 웁니다.
 

코드에서는 똑같이 animal.speak()를 호출했다.

하지만 실제 객체가 Dog이면 멍멍 짖고, Cat이면 야옹 운다.

 

이것이 다형성이다.

같은 메서드 호출
객체에 따라 다른 동작
 

다형성을 사용하면 코드를 더 유연하게 만들 수 있다.

 

예를 들어 새로운 동물인 Bird를 추가한다고 하자.

class Bird(Animal):
    def speak(self):
        print(f"{self.name}가 짹짹 웁니다.")
 

이제 리스트에 Bird를 추가해도 반복문 코드는 바꿀 필요가 없다.

animals = [Dog("초코"), Cat("나비"), Bird("참새")]

for animal in animals:
    animal.speak()
 

출력은 다음과 같다.

초코가 멍멍 짖습니다.
나비가 야옹 웁니다.
참새가 짹짹 웁니다.
 

반복문은 여전히 speak()만 호출한다.

새로운 객체가 추가되어도 기존 흐름을 크게 바꾸지 않아도 된다.

 

다형성의 핵심은 다음과 같다.

같은 인터페이스를 사용한다.
실제 동작은 객체마다 다를 수 있다.
새로운 타입이 추가되어도 기존 코드를 덜 수정하게 된다.
 

추상화

추상화(Abstraction)는 복잡한 내부 구현은 숨기고, 중요한 특징만 드러내는 것이다.

사용자는 내부가 어떻게 동작하는지 몰라도 필요한 기능을 사용할 수 있다.

 

예를 들어 자동차를 운전한다고 하자.

 

운전자는 가속 페달을 밟으면 차가 앞으로 간다는 사실만 알면 된다.

엔진 내부에서 연료가 어떻게 분사되고, 어떤 기계적 과정이 일어나는지 모두 알 필요는 없다.

가속 페달을 밟는다.
자동차가 앞으로 간다.
 

프로그래밍에서도 마찬가지이다.

 

객체를 사용할 때 내부 구현을 모두 알 필요 없이, 외부에 제공된 기능만 사용하면 된다.

 

예를 들어 결제 시스템을 생각해보자.

class Payment:
    def pay(self, amount):
        pass
 

Payment는 결제라는 공통 기능만 정의한다.

 

실제 결제 방식은 카드 결제, 카카오페이 결제, 계좌이체 결제 등으로 나뉠 수 있다.

class CardPayment(Payment):
    def pay(self, amount):
        print(f"카드로 {amount}원을 결제합니다.")


class KakaoPayPayment(Payment):
    def pay(self, amount):
        print(f"카카오페이로 {amount}원을 결제합니다.")
 

사용하는 쪽에서는 구체적인 결제 방식의 내부 구현을 몰라도 된다.

def process_payment(payment, amount):
    payment.pay(amount)
 

payment.pay()를 호출하면 된다.

카드 결제인지, 카카오페이 결제인지는 실제 객체가 결정한다.

 

추상화의 핵심은 다음과 같다.

복잡한 구현을 숨긴다.
사용자에게 필요한 기능만 보여준다.
공통된 개념을 뽑아낸다.
 

추상화를 잘하면 시스템을 더 단순하게 이해할 수 있다.

복잡한 세부 구현보다 “이 객체가 무엇을 할 수 있는가”에 집중할 수 있기 때문이다.

캡슐화와 추상화의 차이

캡슐화와 추상화는 헷갈리기 쉽다.

둘 다 내부를 숨긴다는 느낌이 있기 때문이다.

 

하지만 초점이 조금 다르다.

캡슐화
데이터를 보호하고, 접근을 제한하는 것

추상화
중요한 기능만 드러내고, 복잡한 구현을 숨기는 것
 

캡슐화는 객체 내부 데이터가 함부로 바뀌지 않도록 막는 데 초점이 있다.

추상화는 사용자가 복잡한 내부 과정을 몰라도 기능을 사용할 수 있게 만드는 데 초점이 있다.

 

예를 들어 은행 계좌에서 잔액을 직접 수정하지 못하게 막는 것은 캡슐화에 가깝다.

자동차에서 가속 페달만 밟으면 내부 엔진 원리를 몰라도 차가 움직이는 것은 추상화에 가깝다.

상속과 다형성의 관계

상속과 다형성도 함께 자주 등장한다.

상속은 부모 클래스의 속성과 기능을 자식 클래스가 물려받는 것이다.

다형성은 같은 메서드 호출이 객체에 따라 다르게 동작하는 것이다.

 

상속을 사용하면 다형성을 구현하기 쉬워진다.

 

예를 들어 Animal이라는 부모 클래스가 있고, Dog, Cat, Bird가 이를 상속받는다고 하자.

 

모든 동물은 speak()라는 메서드를 가진다.

 

하지만 실제 동작은 다르다.

Dog.speak()
멍멍

Cat.speak()
야옹

Bird.speak()
짹짹
 

같은 speak()라는 이름을 사용하지만 객체마다 다른 동작을 한다.

이것이 다형성이다.

객체지향 4대 특성 정리

객체지향 4대 특성을 표로 정리하면 다음과 같다.

특성 의미 핵심
캡슐화 데이터와 기능을 묶고 내부 데이터를 보호하는 것 직접 접근 제한
상속 기존 클래스의 속성과 기능을 물려받는 것 코드 재사용
다형성 같은 기능 호출이 객체에 따라 다르게 동작하는 것 유연한 확장
추상화 복잡한 구현을 숨기고 중요한 기능만 드러내는 것 핵심만 표현

각 특성을 짧게 정리하면 다음과 같다.

캡슐화
함부로 건드리면 안 되는 데이터를 보호한다.

상속
공통 기능을 물려받아 재사용한다.

다형성
같은 명령을 내려도 객체마다 다르게 동작한다.

추상화
복잡한 내부 구현을 숨기고 필요한 기능만 보여준다.
 

예시로 한 번에 이해하기

게임 캐릭터를 예로 들어보자.

모든 캐릭터는 이름과 체력을 가진다.

Character
name
hp
attack()
 

전사, 마법사, 궁수는 모두 캐릭터이다.

그래서 Character의 공통 속성과 기능을 상속받을 수 있다.

Warrior는 Character이다.
Mage는 Character이다.
Archer는 Character이다.
 

체력 값은 아무렇게나 바뀌면 안 되므로 외부에서 직접 수정하지 못하게 막는다.

이것은 캡슐화이다.

hp를 직접 수정하지 못하게 한다.
damage() 메서드를 통해서만 체력을 감소시킨다.
 

전사, 마법사, 궁수는 모두 attack()을 할 수 있다.

하지만 공격 방식은 다르다.

전사 attack()
검으로 공격

마법사 attack()
마법으로 공격

궁수 attack()
활로 공격
 

같은 attack() 호출이 객체마다 다르게 동작하므로 다형성이다.

 

사용자는 캐릭터가 어떻게 공격 로직을 계산하는지 모두 알 필요가 없다.

 

그냥 attack()을 호출하면 된다.

 

복잡한 공격 구현을 숨기고 공격이라는 기능만 보여주므로 추상화이다.

정리

객체지향 프로그래밍은 객체를 중심으로 프로그램을 구성하는 방식이다.

객체는 데이터와 기능을 함께 가진다.

 

객체지향의 4대 특성은 캡슐화, 상속, 다형성, 추상화이다.

 

캡슐화는 객체의 데이터와 기능을 하나로 묶고, 내부 데이터에 직접 접근하지 못하게 제한하는 것이다.
데이터를 보호하고, 객체가 정해진 방식으로만 사용되게 만든다.

 

상속은 기존 클래스의 속성과 기능을 새로운 클래스가 물려받는 것이다.
공통 기능을 재사용할 수 있지만, 부모와 자식의 관계가 강하게 묶이므로 신중하게 사용해야 한다.

 

다형성은 같은 메서드 호출이 객체에 따라 다르게 동작하는 성질이다.
새로운 타입이 추가되어도 기존 코드를 덜 수정하게 만들어준다.

 

추상화는 복잡한 내부 구현을 숨기고 중요한 기능만 드러내는 것이다.사용자는 내부 원리를 모두 몰라도 객체가 제공하는 기능을 사용할 수 있다.

 

객체지향 4대 특성은 따로 떨어진 개념이 아니라 함께 사용된다.

 

캡슐화로 데이터를 보호하고, 추상화로 필요한 기능만 드러내며, 상속으로 공통 기능을 재사용하고, 다형성으로 객체마다 다른 동작을 유연하게 처리한다.

 

LIST