software-design

객체 지향

프로그래밍을 처음 시작하면 흔히 듣게 되는 개념이 바로 **객체 지향 프로그래밍(OOP, Object-Oriented Programming)**입니다. 절차지향 프로그래밍이 "어떤 작업을 어떤 순서로 처리할 것인가"에 초점을 맞춘다면, 객체 지향은 "현실 세계의 사물(객체)을 소프트웨어 안에서 어떻게 표현하고 상호작용하게 할 것인가"에 초점을 둡니다. 즉, 프로그램을 객체들의 모임으로 보고 각 객체가 서로 메시지를 주고받으며 동작하도록 설계하는 방식입니다.

객체 지향 프로그래밍을 사용하는 이유는 코드의 재사용성과 유지보수성을 높이고, 현실 세계의 개념을 직관적으로 모델링할 수 있기 때문입니다. 덕분에 작은 프로그램부터 대규모 시스템까지 안정적이고 확장 가능한 구조를 설계할 수 있습니다.

객체 지향이란

객체 지향(Object-Oriented)은 데이터(속성)와 그 데이터를 다루는 기능(메서드)을 하나로 묶어 객체라는 단위로 생각하는 프로그래밍 패러다임입니다. 자동차, 사람, 동물처럼 현실 세계에서 독립적으로 존재하는 개체들을 그대로 프로그램에 반영하는 것과 비슷합니다. 이렇게 하면 프로그램이 단순한 절차의 나열이 아니라, 서로 협력하는 객체들의 집합으로 표현됩니다.

1. 캡슐화 (Encapsulation)

캡슐화는 데이터와 그 데이터를 처리하는 메서드를 하나의 단위(객체)로 묶는 것을 의미합니다. 예를 들어 “자동차” 객체가 있다고 하면, 속도나 연료량 같은 데이터와 가속한다(), 멈춘다() 같은 기능을 하나로 묶어 표현하는 것이 캡슐화입니다.

캡슐화를 적용하면 다음과 같은 장점이 생깁니다.

  • 재사용성 증가: 이미 만든 객체를 다른 프로젝트나 다른 모듈에서도 쉽게 가져다 쓸 수 있습니다.
  • 오류 파급 효과 감소: 객체 내부에서 문제가 발생해도 외부에는 최소한의 영향만 미치도록 차단할 수 있습니다.
  • 인터페이스 단순화: 내부 구현은 감추고, 외부에는 필요한 메서드만 노출해 결합도를 낮춥니다.

또한 정보 은닉(Information Hiding)은 캡슐화의 중요한 특징입니다. 객체는 자신의 내부 데이터를 직접 노출하지 않고, 반드시 공개된 메서드를 통해서만 접근하도록 합니다. 예를 들어 자동차 객체의 속도 값을 외부에서 직접 수정할 수 없고, 반드시 가속한다()감속한다() 같은 메서드를 통해서만 바꿀 수 있도록 설계하는 것입니다. 이렇게 하면 잘못된 접근으로부터 데이터를 보호하고, 내부 구현을 자유롭게 변경하더라도 외부 코드에는 영향을 주지 않게 됩니다.

3. 상속 (Inheritance)

상속은 상위(부모) 클래스의 속성(데이터)과 연산(메서드)을 하위(자식) 클래스가 그대로 물려받아 사용하는 개념입니다. 공통된 기능을 부모 클래스에 정의해두면, 자식 클래스에서 이를 재사용할 수 있어 코드의 중복을 줄이고 관리가 쉬워집니다. 또한 자식 클래스는 부모로부터 물려받은 기능을 그대로 사용하거나, 필요에 따라 재정의(오버라이딩) 하여 더 구체적인 동작을 구현할 수도 있습니다.

예를 들어, 동물 클래스를 부모로 두고 개, 고양이, 토끼 같은 클래스를 자식으로 두면, 모든 동물에게 공통적인 먹다(), 움직이다() 같은 메서드는 부모 클래스에서 정의하고, 개 클래스에서는 짖다(), 고양이 클래스에서는 야옹하다()처럼 고유한 기능을 확장할 수 있습니다.

4. 추상화 (Abstraction)

추상화는 복잡한 현실 세계를 그대로 모델링하는 대신, 필요한 속성과 기능만 선별해 단순하게 표현하는 과정입니다. 불필요한 세부 사항을 숨기고 핵심만 드러내어 시스템을 더 쉽게 이해하고 설계할 수 있게 해줍니다.

예를 들어 “자동차”를 추상화한다고 할 때, 우리는 엔진의 나사 구조까지 모델링할 필요는 없습니다. 대신 자동차의 핵심 속성인 브랜드, 색상, 속도와 같은 속성, 그리고 달린다(), 멈춘다() 같은 기능만 정의하면 충분합니다. 추상화를 통해 프로그램은 현실의 복잡성을 줄이고, 필수적인 공통 요소만을 기반으로 재사용성과 확장성을 높일 수 있습니다.

5. 다형성 (Polymorphism)

다형성은 같은 메서드 호출이 객체의 타입이나 상황에 따라 서로 다르게 동작할 수 있는 성질을 말합니다. 예를 들어 draw()라는 메서드를 호출했을 때, 원(circle) 객체는 원을 그리고 사각형(rectangle) 객체는 사각형을 그리는 식으로 결과가 달라집니다. 이는 오버로딩(메서드 이름은 같지만 매개변수가 다른 경우)과 오버라이딩(상속받은 메서드를 자식 클래스에서 재정의하는 경우)으로 구현되며, 유연성과 확장성을 제공하여 다양한 요구사항을 효과적으로 처리할 수 있게 해줍니다.


정리

객체 지향 프로그래밍(OOP)의 핵심은 캡슐화, 상속, 추상화, 다형성이며, 이를 통해 복잡한 시스템을 구조적으로 단순화하고 재사용성을 높일 수 있습니다. 특히 캡슐화는 데이터와 메서드를 하나로 묶어 결합도를 낮추고, 정보 은닉을 통해 내부 구현을 숨겨 안정성을 강화합니다. 상속은 기존 코드를 재활용하여 유지보수 효율을 높이고, 추상화는 불필요한 요소를 제거해 핵심 기능만 표현함으로써 이해도를 높입니다.

또한 다형성은 동일한 메서드 호출이 객체의 종류에 따라 다르게 동작하도록 해 유연성과 확장성을 제공합니다. 이러한 특성들은 단순한 코드 재사용을 넘어, 시스템 전체의 안정성·확장성·유지보수성을 높여주는 객체 지향 프로그래밍의 핵심적인 가치라고 할 수 있습니다.