프로그래밍

객체 지향이란 무엇인가 - 절차지향과의 차이점

Jay Tech 2019. 5. 15. 17:29
반응형

객체지향 개념 간단 정리

본 내용은 "개발자가 반드시 정복해야할 객체 지향과 디자인 패턴 - 최범균" 을 읽으며 정리한 내용입니다.

1. 절차 지향과 객체 지향

1.1 절차지향

절차지향이란 프로시져(procedure)로 프로그램을 구성하는 기법이다. 프로시져는 대체로 데이터를 중심으로 구현한다. 단점은 데이터 타입이나 의미를 변경해야 할 때, 함께 수정해야 하는 프로시저가 증가하는 것이다.

1.2 객체 지향

객체는 자신만의 데이터와 프로시져를 갖는다. 객체는 자신만이 기능을 제공하며, 각 객체들은 서로 연결되어 다른 객체가 제공하는 기능을 사용할 수 있다.

2. 객체

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

객체 지향의 가장 기본은 객체이다. 예를들어, 소리 크기 제어 객체가 있다고 생각하면 이 객체가 제공하는 기능은 다음과 같을 것이다.

  • 소리 크기 증가

  • 소리 크키 감소

  • 음소거

이 객체가 내부적으로 어떤 데이터 타입 값으로 보관하는 지는 알 수 없다. 하지만 저 기능을 제공하는 것이 중요할 뿐이다.

2.2 인터페이스와 클래스

객체가 제공하는 기능은 오퍼레이션이라고 한다. 객체자 제공하는 모든 오퍼레이션 집합을 객체의 인터페이스(interface)라고 한다. 여기서 말하는 인터페이스라함은 언어 별로 있는 인터페이스 예약어를 의미하는 것이 아니라 객치제향에서 오퍼레이션의 집합을 표현할 때 사용하는 용어이다.

2.3 메세지

자바와 같은 언어에서는 메서드를 호출하는 것이 메세지를 보내는 과정에 해당한다.

FileInputStream is = new FileInputStream(fileName);
byte[] data = new byte[512];
int readBytes = is.read(data);

is가 참조하는 객체에 read() 오퍼레이션을 실행해 달라는 메세지 를 전송하는 것이다.

3. 객체의 책임과 크기

객체는 객체가 가지고 있는 기능으로 정의되는데, 이것은 자신만의 책임이 있다는 의미를 가진다. 한 객체가 갖는 책임을 정의한것이 인터페이스라고 했었다. 객체지향적으로 프로그래밍을 할 때 가장 어려우면서 중요한 것이 바로 객체이다.

객체가 갖는 책임의 크기는 작을 수록 좋다. 객체자 갖는 책임이 작아야 한다는 것은 객체가 제공하는 기능의 개수가 적다는 것을 의미한다.

한 객체에 많은 기능들이 포함되면 기 기능과 관련되 ㄴ데이터들도 한 객체에 모두 포함된다. 이 구조는 객체에 정의된 많은 오퍼레이션들이 데이터를 공유하는 방식으로 프로그래밍된다는 것을 의미하는데, 이것은 곧 데이터를 중심으로 개발되는 절차 지향 방식과 동일한 구조가 된다. 절차지향의 가장 큰 문제는 변경의 어려움 문제 (경직성 문제라고도 한다)가 있다. 따라서 객체가 갖는 책임의 크기는 작아질수록 좋다.

4. 의존

객체 지향적으로 프로그램을 구현하다 보면, 다른 객체가 제공하는 기능을 이용해서 자신의 기능을 완성하는 객체가 출현하게 된다. 한 객체가 다른 객체를 이용한다는 것은, 실제 구현에서는 한 객체의 코드에서 다른 객체를 생성하거나 다른 객체의 메서드를 호출한다는 것을 뜻한다. 이렇게 한 객체가 다른 객체를 생성하거나 다른 객체의 메서드를 호출할 때 이를 그 객체에 의존한다고 한다. (dependency)

4.1 의존의 양면성

  • 내가 변경되면 나에게 의존하고 있는 다른 코드에 영향을 준다.

  • 나의 요구가 변경되면 내가 의존하고 있는 타입에 영향을 준다.

5. 캡슐화

5.1 절차 지향 코드

캡슐화(encapsulation)는 객체가 내부적으로 기능을 어떻게 구현하는지를 감추는 것이다.

if (member.getExpirationDate != null && member.getExpirationDate.getDate() < System.currentTimeMillis()) {
	// logic
}

이런식으로 프로그래밍 되었다고 해보자. 하지만 서비스 운영 도중 만료기간에 대한 조건들이 많이 추가될 수 가 있다. 그럼 if 문 안의 로직이 매우 늘어나게 된다. 이런 문제는 데이터를 중심으로 프로그래밍 했기 때문이다. 즉, 절차 지향적으로 만들었기 때문이다.

5.2 캡슐화 된 기능 구현

캡슐화는 기능이 내부적으로 어떻게 구현 되었는지 숨기는 것이다.

public class Memeber {
  ...

  public boolean isExpired() {
  	// logic
  }
}

// 그리고 실제 이용 부분은

if (member.isExpired()) {
	// logic
}

이렇게 처리할 수 있다. 그렇다면 기능 변경에 대한 부분은 isExpired() 함수를 수정해주면 된다. Member 클래스 안에 만료되었는지의 함수를 숨기는 것이다. 내부 구현은 몰라도 되고 이용할 때 isExpired()를 써주면 되는 것이다.

5.3 캡슐화를 위한 두 가지 규칙

  • Tell, Don't ask

  • 데미테르의 법칙 (Law of Demeter)

Tell, Don't ask는 데이터를 물어보지 않고 기능을 실행해 달라고 말하는 규칙이다. (위의 예) 쉽게 말하면 필드에 대한 get 메서드를 최대한 쓰지 않도록 하면 좋다.

데미테르의 법칙은 위의 내용을 잘 지킬 수 있게 해준다.

 

  • 메서드에서 생성한 객체의 메서드만 호출

  • 파라미터로 받은 객체의 메서드만 호출

  • 필드로 참조하는 객체의 메서드만 호출

반응형