객체 지향 프로그래밍 (Object Oriented Programming) 정리

Jiwoo Jung·2026년 1월 8일

객체?

실제 세계의 객체를 생각하면 된다 → 어떠한 상태(속성)를 갖고 특정 행위를 할 수 있는 독립적인 단위.

Class

객체의 설계도, 속성과 동작을 정의한다.

사용자 정의 자료형(user defined data type)

Object

상태(데이터)와 행동(메소드)를 함께 가지는 독립적인 단위

Class → Instantiate → Object

실제 메모리에 할당된 인스턴스


객체 지향 프로그래밍 (Object Oriented Programming)

객체 중심의 프로그래밍 패러다임.

프로그램을 여러개의 객체로 구성된 시스템으로 바라보는 방식


필요성

절차 지향 프로그래밍(Procedure Oriented Programming)

  • 함수가 프로그램의 기본 단위이다.
    • 프로그램이 수행해야 할 일들을 순서대로 나열하고, 각 작업을 독립적인 함수로 분리하여 작성한다.
  • 데이터와 함수가 분리되어있다.

장점

  • 실행 흐름이 직관적이고 이해하기 쉽다.
  • 실행 속도가 빠르다. 하드웨어 제어에 유리하다.
  • 작은 규모의 프로그램 개발 / 프로토타입 개발에 유리하다.

단점

  • 중복 코드가 발생하기 쉽고, 코드의 재사용성이 낮다
  • 데이터 보호가 어렵다. (책임 및 권한의 분리가 어렵다.)
  • 잦은 전역변수 사용으로 오류가 발생하기 쉽다.
  • 유지보수가 어렵다.

객체 지향 프로그래밍

장점

  • 코드의 재사용이 쉽다.
  • 상속, 다형성 → 기능 확장이 쉽다.
  • 프로그램을 모듈화할 수 있어 유지보수가 편리하다.
  • 대규모 SW 개발에 적합하다.
  • 실제 세계의 사물이나 개념을 프로그램에 표현할 수 있다.

단점

  • 설계 단계가 복잡하다(요구사항 분석, 모델링).
  • 추상화, 메모리 → 실행속도 느림.
  • 학습곡선

특징

1. 캡슐화(Encapsulation)

데이터를 외부에서 직접 접근하지 못하게 하고, 메소드를 통해서만 접근할 수 있게 제한하는 개념.

데이터 + 메서드를 객체로 캡슐화하고, 외부에서는 객체 내부를 알 수 없도록 숨긴다.

파이썬의 캡슐화

완전히 기술적으로 막지는 않고, 관례로 구현된다. → 파이썬의 철학: “we are consenting adults here”

Protected: _ 클래스 및 하위 클래스에서 접근 가능.

class Person():
    def __init__(self, name):
        self._name = name

Private: __ (name mangling) 정의한 클래스 내에서만 접근 가능.

class Person():
    def __init__(self, name):
        self.__name = 0

@property

class User:
    def __init__(self, age):
        self._age = age

    @property
    def age(self):
        print("getter 호출")
        return self._age

    @age.setter
    def age(self, value):
        print("setter 호출")
        if value < 0:
            raise ValueError("나이는 음수 불가")
        self._age = value
u = User(20)

u.age        # getter 호출
u.age = 30   # setter 호출
u.age  ──>  getter(age) ──>  _age
u.age= ──>  setter(age) ──>  _age

접근 경로가 통제된다.

2. 추상화(Abstraction)

객체가 제공하는 행동(기능)만 드러내고, 내부 구현을 숨기는 설계 방식.

외부에서 객체의 내부 구현은 몰라도 된다. 객체 외부에서 메소드를 사용하는 사람은 구현 내용을 몰라도 사용할 수 있다.

3. 상속(Inheritance)

기존에 작성된 클래스의 속성과 메소드를 물려받아 사용할 수 있다.

기존 코드를 재사용할 수 있다. 상속을 통해 다형성을 구현할 수 있다.

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

    def move(self):
        print(f"{self.name} 이동중")

class Car(Vehicle):
    def __init__(self, name, wheels):
        super().__init__(name)
        self.wheels=wheels
        
    def info(self):
        print(f"{self.name} 바퀴는 {self.wheels}개")

def practice_inheritance():
    banner("3) OOP: Inheritance")

    car = Car("Taxi", 4)
    car.move()   # 예상: Taxi 이동 중
    car.info()   # 예상: Taxi 바퀴는 4개

4. 다형성(polymorphism)

하나의 메소드/클래스가 다양하게 동작할 수 있다.

오버라이딩(상속받은 메소드 재정의), 오버로딩(매개변수에 따라 여러개 정의)

# w/o polymorphism

class Dog:
		def __init__(self, name):
				self.name = name
		
		def bark(self):
				return f"{self.name} says Woof!"

class Cat:
		def __init__(self, name):
				self.name = name
		
		def meow(self):
				return f"{self.name} says Meow!"
				
def make_animal_speak(animal):
		if isinstance(animal, Dog):
				print(animal.bark())
		elif isinstance(animal, Cat):
				print(animal.meow())
		else:
				raise ValueError("Unknown animal")
				
# with polymorphism

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

class Dog(Animal):
		def speak(self):
				return f"{self.name} says Woof!"

class Cat(Animal):
		def speak(self):
				return f"{self.name} says Meow!"
				
def make_animal_speak(animal):
		print(animal.speak())

dog = Dog("Buddy")
cat = Cat("Whiskers")
make_animal_speak(dog)
make_animal_speak(cat)

같은 기능을 하는 메서드 이름을 같게 → 복잡성 줄이고, 코드 재사용, 기능 확장 용이

참고자료

1.3. 절차지향 언어 vs 객체지향 언어

0개의 댓글