콘텐츠로 건너뛰기

객체지향 프로그래밍(OOP)

객체 지향 프로그래밍(Object-Oriented Programming, OOP)은 현대 소프트웨어 개발에서 가장 중요한 프로그래밍 패러다임 중 하나이다.
이번 시간에는 OOP의 핵심 개념, 특징, 장단점, 그리고 실제 적용 사례에 대해 알아보자.

OOP란?

객체 지향 프로그래밍은 컴퓨터 프로그램을 명령어의 목록으로 보는 시각에서 벗어나 여러 개의 독립된 단위, 즉 “객체”들의 모임으로 파악하고자 하는 프로그래밍 패러다임이다.
좀 더 구체적으로 말하자면, 프로그래밍에서 필요한 데이터를 추상화시켜 상태와 행위를 가진 객체를 만들고 그 객체들 간의 유기적인 상호작용을 통해 로직을 구성하는 프로그래밍 방법이라고 할 수 있다.

OOP는 여러 독립적인 부품들의 조합, 즉 객체들의 유기적인 협력과 결합으로 프로그램을 파악하고자 한다.
마치 자동차를 만들 때 수많은 부품들을 결합하여 완성된 자동차를 만드는 것과 같이, 소프트웨어를 각각의 객체라는 작은 부품들로 나누고 이들을 조립하여 완성된 프로그램을 만드는 방식이다.

객체란?

객체는 OOP의 가장 기본적인 단위이자 시작점이다.
객체는 상태(state)와 행위(behavior)를 가진 데이터의 집합으로, 우리가 보고 느끼고 인지할 수 있는 모든 것을 의미한다.
일상생활에서 볼 수 있는 책상, 의자, 사람 등 모든 실재하는 대상뿐만 아니라, 눈에 보이지 않는 논리, 개념, 공식 등도 객체가 될 수 있다.

프로그래밍에서 객체는 속성(변수)과 기능(메소드)을 가진 모듈로 구현된다.
예를 들어, “자동차” 객체는 색상, 모델, 제조사 등의 속성과 주행, 정지 등의 기능을 가질 수 있다.

4가지 특징

객체 지향 프로그래밍은 4가지 특징을 가지고 있다.

1. 추상화(Abstraction)

추상화: 불필요한 정보는 숨기고 중요한 정보만을 표현하여 간단히 만드는 것
객체들의 공통된 속성과 행위(필요한 정보)를 묶어 클래스로 설계하는 과정 자체를 의미한다.
예를 들어, 여러 종류의 자동차(벤츠, 아우디, 티코 등)에서 공통적인 특성(바퀴, 핸들, 차문 등)을 추출하여 “자동차” 클래스를 정의하는 것, 바로 이것이 추상화이다.

2. 캡슐화(Encapsulation)

캡슐화: 객체의 속성과 행위를 하나로 묶고, 구현 코드를 외부에 감추어 은닉하는 것
캡슐화를 통해 객체의 내부 구현을 외부로부터 보호하고, 필요한 부분만 외부에 노출시킨다.
이를 통해 객체의 응집도와 독립성을 높이고 모듈화를 지향할 수 있다.

캡슐화의 중요한 목적은 정보 은닉이다.
예를 들어, 사용자 정보를 가지고 있는 객체에서 중요한 데이터를 private으로 설정하여 보호하고, getter나 setter 메서드를 통해서만 간접적으로 접근할 수 있게 한다.

3. 상속(Inheritance)

상속: 상위 클래스의 속성과 기능을 하위 클래스가 물려받아 사용하는 것
상속을 통해 코드의 재사용성을 높이고, 중복을 줄일 수 있다.
예를 들어, “자동차” 클래스를 상속받아 “스포츠카”, “SUV” 등의 특화된 자동차 클래스를 만들 수 있다.

* Java와 같은 언어에서는 다중 상속을 지원하지 않는데, 이는 다이아몬드 문제(두 부모 클래스에서 같은 이름의 메서드를 각각 오버라이딩했을 때 자식 클래스가 어느 부모의 메서드를 사용해야 할지 모르는 문제)를 방지하기 위함이라고 한다.

4. 다형성(Polymorphism)

다형성: 하나의 변수명, 함수명 등이 상황에 따라 다른 의미로 해석될 수 있는 것
다형성은 주로 오버라이딩(Overriding)과 오버로딩(Overloading)을 통해 구현된다.

  • 오버라이딩: 부모 클래스의 메서드를 자식 클래스에서 같은 이름과 매개변수로 재정의하는 것
  • 오버로딩: 같은 이름의 함수를 여러 개 정의하고, 매개변수의 타입과 개수를 다르게 하여 다양한 호출 방식을 지원하는 것

다형성을 통해 코드의 재사용성을 높이고, 확장성을 확보할 수 있다.

OOP vs 절차적 프로그래밍

객체 지향 프로그래밍의 특징을 더 잘 이해하기 위해, 이전 패러다임인 절차적 프로그래밍과 비교해보자.

절차적 프로그래밍의 한계

초기에 등장한 순차적 프로그래밍은 코드의 흐름과 순서에 기반한 프로그래밍 방식이다.
직관적이라는 장점이 있지만, 프로젝트 규모가 커지면 goto 문이 범람하여 스파게티 코드가 되는 문제가 있다.

이후 등장한 절차적 프로그래밍에서는 반복되는 코드를 함수(프로시저) 단위로 모듈화했지만 여전히 데이터와 함수가 분리되어 있어, 특정 객체에 관련된 데이터와 기능을 하나로 관리하기 어려웠다.

절차적 프로그래밍의 한계점 극복, OOP

OOP는 데이터와 함수를 객체라는 단위로 묶어 관리함으로써 이러한 문제를 해결했다.
이는 우리가 일상에서 사용하는 언어 구조와 더 유사하다.
예를 들어, “고객이 돈을 지불한다” 또는 “자판기가 제품을 제공한다”와 같이 객체 중심으로 프로그램을 구성할 수 있다.

OOP의 장단점

장점

  1. 코드 재사용성이 높음: 상속을 통해 기존 코드를 재사용하고 확장할 수 있다.
  2. 유지보수가 용이함: 객체 단위로 모듈화되어 있어, 특정 부분에 문제가 생겼을 때 해당 객체만 수정하면 된다.
  3. 확장성이 좋음: 기존 코드를 변경하지 않고도 새로운 기능을 추가할 수 있다.
  4. 대형 프로젝트에 적합: 클래스 단위로 모듈화하여 여러 개발자가 협업하기 좋다.
  5. 가독성이 높음: 객체 중심으로 코드가 구성되어 의미 파악이 쉽다.
  6. 프로그램을 보다 유연하고 변경이 용이하게 만듦: 객체 간의 독립성이 높아 코드 변경의 영향 범위가 제한적이다.

단점

  1. 처리 속도가 상대적으로 느림: 객체 간의 메시지 전달과 다형성 구현 등으로 인해 실행 속도가 저하될 수 있다.
  2. 메모리 사용량이 증가: 객체가 많아지면 프로그램 용량이 커질 수 있다.
  3. 설계 시 많은 시간과 노력이 필요: 객체 모델링과 클래스 설계에 많은 비용이 든다.
  4. 작은 규모의 프로젝트에서는 비효율적일 수 있음: 간단한 프로그램에서는 설계 과정이 오히려 부담이 될 수 있다.
  5. 임베디드 같은 특정 분야에 부적합: 극도로 빠른 실행 속도나 제한된 자원이 요구되는 환경에서는 비효율적일 수 있다.

OOP의 활용

게임 개발

게임 개발에서는 캐릭터, 아이템, 환경 등을 각각 객체로 모델링한다.
예를 들어, 게임 캐릭터를 구현할 때 ‘전사’, ‘마법사’, ‘궁수’ 등의 캐릭터 클래스가 있을 경우, 각 캐릭터마다 고유한 능력치와 행동 방식을 정의하고 이를 상속받아 다양한 캐릭터들을 구현할 수 있다.

웹 애플리케이션

웹 애플리케이션에서는 사용자 정보나 상품 정보를 각각 클래스(예: User, Product)로 모델링하여 관리한다.
이를 통해 데이터베이스와 연동하여 CRUD(Create, Read, Update, Delete) 작업을 효율적으로 수행할 수 있다.

예시

헬스장 시스템에서 회원의 근육량과 피로도를 관리하는 클래스를 만들 수 있다.
TypeScript를 사용한 실제 코드 예시를 보자.
(아래 예시에서는 OOP의 캡슐화를 통해 헬스장 회원의 데이터와 운동 기능을 하나의 클래스로 묶었다)

class Gym {
  // 회원 정보와 관련된 속성과 메서드를 캡슐화
  private muscles: number;
  private fatigability: number;
  private deltaPerHour: number;

  constructor() {
    this.muscles = 0;
    this.fatigability = 50;
    this.deltaPerHour = 10;
  }

  workout(hours: number) {
    if (this.fatigability >= 100) {
      console.log('Too Tired to Workout! Need to Rest!');
      return;
    }

    this.muscles += hours * this.deltaPerHour;
    this.fatigability += hours * this.deltaPerHour;

    return {
      muscles: this.muscles,
      fatigability: this.fatigability
    };
  }
}

결론

객체 지향 프로그래밍은 소프트웨어 개발의 복잡성을 관리하고, 코드의 재사용성과 유지보수성을 향상시키는 강력한 패러다임이다.
추상화, 캡슐화, 상속, 다형성이라는 네 가지 특징을 통해 실제 세계의 문제를 자연스럽게 모델링하고 효율적으로 해결할 수 있게 해준다.

물론 모든 상황에 적합한 것은 아니다.
작은 규모의 프로젝트나 성능이 중요한 분야에서는 다른 패러다임이 더 효율적일 수 있다.
그러나 현대의 복잡하고 대규모 소프트웨어 개발에서는 OOP가 제공하는 구조화된 접근 방식이 큰 장점을 발휘한다.

그렇다. 결국, 개발자인 우리가 문제의 특성과 요구사항을 고려해서 적절한 프로그래밍 패러다임을 선택해야 한다.

0 를 눌러주세요! 행복해져요!

답글 남기기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다