프로그래밍-학습기록/객체 지향 프로그래밍

객체 지향

leesche 2021. 1. 5. 20:41

객체 지향

절차 지향과 객체 지향

절차(프로시저) 지향 프로그램은 데이터를 중심으로 한 프로시저로 구성된다. 프로그램 규모가 커져서 데이터 종류가 증가하고 이를 사용하는 프로시저가 증가하게 되면, 다음과 같은 문제들이 발생하게 된다.

  • 데이터 타입이나 의미를 변경해야 할 때, 함께 수정해야 하는 프로시저가 증가한다.
  • 같은 데이터를 프로시저들이 서로 다른 의미로 사용하는 경우가 발생한다.

이는 결국 코드의 수정을 어렵게 만들며, 새로운 기능을 추가하는데 많은 구현 시간(즉, 개발 비용)을 투입하게 만든다.

이런 절차 지향과 달리 객체 지향 프로그램은 데이터 및 데이터와 관련된 프로시저를 객체(object)라고 불리는 단위로 묶는다. 객체는 프로시저를 실행하는데 필요한 만큼의 데이터를 가지며, 객체들이 모여 프로그램을 구성한다.

각 객체는 자신만의 데이터와 프로시저를 갖는다. 객체는 자신만의 기능을 제공하며, 각 객체들은 서로 연결되어 다른 객체가 제공하는 기능을 사용할 수 있게 된다. 객체는 다른 객체에 기능을 제공하기 위해 프로시저는 자신이 속한 객체의 데이터에만 접근할 수 있으며, 다른 객체에 속한 데이터에는 접근할 수 없다.

객체 지향으로 만든 코드에서는 객체의 데이터를 변경하더라도 해당 객체로만 변화가 집중되고 다른 객체에는 영향을 주지 않기 때문에 요구 사항의 변화가 발생했을 때 절차 지향 방식보다 프로그램을 더 쉽게 변경할 수 있는 장점을 갖는다.

객체

객체의 핵심은 기능을 제공하는 것

인터페이스와 클래스

보통 객체가 제공하는 기능을 오퍼레이션(operation)이라고 부른다. 즉, 객체는 오퍼레이션으로 정의가 된다. 객체가 제공하는 기능을 사용한다는 것은 결국 객체의 오퍼레이션을 사용한다는 의미가 된다. 그런데, 객체가 제공하는 오퍼레이션을 사용할 수 있으려면, 그 오퍼레이션의 사용법을 알아야 한다. 이 사용법은 일반적으로 세 개로 구성되며, 이 세 가지를 합쳐서 시그니처(Signature)라고 부른다.

  • 기능 식별 이름
  • 파라미터 및 파라미터 타입
  • 기능 실행 결과 값

객체가 제공하는 모든 오퍼레이션의 집합을 '인터페이스(interface)'라고 부르며, 서로 다른 인터페이스를 구분할 때 사용되는 명칭이 바로 타입(type)이다. 여기서 말하는 인터페이스는 자바 언어에 포함되어 있는 인터페이스가 아니라, 객체 지향에서 오퍼레이션 집합을 표현할 때 사용되는 용어이다. 인터페이스는 객체를 사용하기 위한 일종의 명세나 규칙이라고 생각하면 된다.

인터페이스는 객체가 제공하는 기능에 대한 명세서일 뿐이다. 실제 객체가 기능을 어떻게 구현하는지에 대한 내용은 포함하고 있지 않다. 실제 객체의 구현을 정의하는 것은 클래스(class)이다.

메시지

오퍼레이션의 실행을 요청(request)하는 것을 '메시지(message)를 보낸다'고 표현한다. 자바와 같은 언어에서는 메서드를 호출하는 것이 메시지를 보내는 과정에 해당된다.

객체의 책임과 크기

객체가 어떤 책임을 질지 결정하기 위해 필요한 기능 목록을 정리해야 한다. 이 기능을 어떻게 객체들에게 분배하느냐에 따라 객체의 구성이 달라진다.

객체가 갖는 책임의 크기는 작을수록 좋다. 객체가 갖는 책임이 작다는 것은 객체가 제공하는 기능의 개수가 적다는 것을 의미한다. 한 객체에 많은 기능이 포함되면, 이는 곧 데이터를 중심으로 개발되는 절차 지향 방식과 동일한 구조가 된다. 따라서 객체가 갖는 책임이 커질수록 절차 지향적으로 구조가 변질되며, 절차 지향의 가장 큰 단점인 기능 변경의 어려움 문제가 발생하게 된다.

의존

한 객체가 다른 객체를 생성하거나 다른 객체의 메서드를 호출할 때, 이를 그 객체에 의존한다고 표현한다.

객체를 생성하든 메서드를 호출하든 또는 파라미터로 전달 받든 다른 타입에 의존을 한다는 것은 의존하는 타입에 변경이 발생할 때 나도 함께 변경될 가능성이 높다는 것을 뜻한다.

의존의 이런 특징 때문에 의존이 순환해서 발생할 경우 다른 방법이 없는지 고민해야 한다.

캡슐화

캡슐화는 객체가 내부적으로 기능을 어떻게 구현하는지를 감추는 것이다. 이를 통해 내부의 기능 구현이 변경되더라도 그 기능을 사용하는 코드는 영향을 받지 않도록 만들어 준다. 즉, 내부 구현 변경의 유연함을 주는 기법이 바로 캡슐화이다.

캡슐화를 위한 두 개의 규칙

  • Tell, Don't Ask

    데이터를 물어보지 않고, 기능을 실행해 달라 하기. 데이터 대신에 기능을 실행해달라고 명령을 내리려면 해당 데이터를 가진 객체에게 기능을 요청해야 한다.

  • 데미테르의 법칙

    데미테르의 법칙은 다음과 같이 간단한 규칙으로 구성된다.

    • 메서드에서 생성한 객체의 메서드만 호출
    • 파라미터로 받은 객체의 메서드만 호출
    • 필드로 참조하는 객체의 메서드만 호출

객체 지향 설계 과정

객체 지향 설계란 다음의 작업을 반복하는 과정이라 볼 수 있다.

  1. 제공해야 할 기능을 찾고 또는 세분화하고, 그 기능에 알맞은 객체에 할당한다.
    1. 기능을 구현하는데 필요한 데이터를 객체에 추가한다. 객체에 데이터를 먼저 추가하고 그 데이터를 이용하는 기능을 넣을 수도 있다.
    2. 기능은 최대한 캡슐화해서 구현한다.
  2. 객체 간에 어떻게 메시지를 주고받을지 결정한다.
  3. 과정1과 과정2를 개발하는 동안 지속적으로 반복한다.

출처

  • 책 <개발자가 반드시 정복해야 할 객체 지향과 디자인 패턴> 2장 객체 지향