이 글은, 나태웅님 “객체 지향 프로그래밍의 4가지 특징” 글을 참고하여 작성한 글입니다.

객체 지향 프로그래밍이란 무엇인가? 라는 물음에 답하기란 생각보다 까다롭다. 객체의 사전적 의미는 “실제로 존재하는 것”이다. 그렇다면 객체 지향 프로그래밍은 “실제로 존재하는 것 처럼 프로그래밍을 하자!” 인 것인가? 나는 “그렇다.” 라고 답할 것 같다.

실제 세계에서 복잡한 무언가를 만들때 우리는 여러 개의 부품들을 조합하여 만든다. 예를 들어, 자동차를 만든다고 생각해보자. 우리는 타이어, 프레임, 핸들, 엔진 등 여러 부품들을 만들고 각 부품들을 정해진 순서대로 조합하여 완성한다. 이 예시에서 우리는 객체가 무엇을 의미하는지 쉽게 알 수 있다(부품 = 객체).

좋다, 다시 돌아와서 물음에 답해보자. 객체 지향 프로그래밍이란? 컴퓨터 프로그램을 순차적인 명령어 처리의 시각에서 벗어나 여러 “객체”라는 독립적인 부품들의 조합으로 바라보는 일종의 패러다임이다. 객체 지향적으로 프로그램을 설계하면 여러 이점이 따른다. 그 중 가장 큰 이점은 바로 유지보수성이다. 시시때때로 변화하는 요구사항에 맞추어 프로그램을 설계하기 위해서는 보다 유연하게 변경이 가능하고 오류에 대처하기 쉬워야 하는데 객체 지향은 이를 가능케 한다. 마치, 자동차 타이어에 문제가 생기면 타이어만 교체하거나 구매자의 요구에따라 옵션을 추가하거나 뺄 수 있듯이 프로그램 요구사항 변화에 따른 변경을 최소화하고 유지보수를 하는 데 유리한 것이다. 더불어서 코드의 재사용성을 높여 코드의 중복을 최소화하고 최대한 간결하게 표현할 수 있다.

앞서 말했듯이 실제로 존재하는 이 세계를 프로그램에 반영하기 위해 발전한 만큼 복잡한 프로그램이라도 인간 친화적이고 직관적으로 코드를 작성할 수 있다. 마치 인류가 발전하여 효율적인 분업이 등장하고 여러 산업의 유기적인 상호작용을 통해 더 크게 번성할 수 있던 것과 같이 말이다(너무 나갔나?).

객체 지향 프로그래밍의 특징

앞서, 우리는 객체 지향 프로그래밍이 객체 - “실제 존재하는 것”을 프로그램에 반영하고 이들간의 유기적인 상호작용을 규정하여 보다 복잡한 프로그램을 조금 더 직관적이고 친화적이게 만드는 방법론임을 알아보았다. 객체 지향이 왜 이점을 가질 수 있는 걸까? 그것은 앞으로 살펴볼 객체 지향의 4가지 특징에서 기인한다.


1. 추상화

추상이란, 사전적의미로 “사물이나 표상(表象)을 어떤 성질·공통성·본질에 착안하여 그것을 추출(抽出)하여 파악하는 것”이다. 여기서 우리가 주목해야할 단어는 “공통성”과 “추출”이다. 이에 조금 더 나아가 객체 지향에서의 추상화란, “객체의 공통적인 속성과 기능을 추출하여 정의하는 것”을 의미한다.

지하철 노선도

지하철 노선도

현실에서 추상화의 예시는 지하철 노선도에서 쉽게 찾아볼 수 있다. 지하철 노선도를 보면 색깔로 구분된 선과 점 그리고 역 이름을 나타내는 글자만으로 이루어져있다. 이처럼 우리에게 필요한 정보만 남겨두고 공통적인 부분들을 추출하여 보여주는 노선도가 추상화의 좋은 예시라고 할 수 있다.

다시 돌아와서, 객체지향 프로그래밍에서 추상화를 찾아보자. 프로그램에서 자동차와 오토바이의 기능을 구현해야 한다고 생각해보자. 둘의 공통적인 속성은 바퀴를 가진 이동수단이며 모든 이동수단은 전진과 후진이 가능하다. 그렇다면 우리는 자동차와 오토바이에서 이동수단이라는 공통적인 속성에서 전진과 후진이라는 동작을 추출할 수 있다. 프로그래밍 언어로 표현하면 자동차와 오토바이(하위클래스)들의 공통적인 동작(전진, 후진)을 추출하여 이동수단(상위클래스)을 정의할 수 있다.

public interface Vehicle {
	void moveForward();
	void moveBackward();
}

<aside> 💡 Interface란, 컴퓨터 프로그래밍에서 “서로 다른 두 시스템, 장치, 소프트웨어 등을 서로 이어주는 부분 또는 그런 접속 장치”라고 정의할 수 있는데, 객체 지향적 설계에 있어서 인터페이스는 어떤 객체의 역할만을 정의하여 객체들 간의 관계를 보다 유연하게 연결하는 역할을 담당한다. 간단히, 어떤 객체가 수행해야 하는 핵심적인 역할만을 규정하고 실제 구현은 인터페이스를 구현하는 각 객체에서 하도록 설계하는 것이다.

</aside>

public class Car implements Vehicle {
	@Override
	public void moveForward() {
		System.out.println("자동차가 전진 합니다.");
	}

	@Override
	public void moveBackward() {
		System.out.println("자동차가 후진 합니다.");
	}
}
public class MotorCycle implements Vehicle {
	@Override
	public void moveForward() {
		System.out.println("오도방구가 전진 합니다.");
	}

	@Override
	public void moveBackward() {
		System.out.println("오도방구가 후진 합니다.");
	}
}