메뉴 바로가기 검색 및 카테고리 바로가기 본문 바로가기

한빛출판네트워크

IT/모바일

객체지향 프로그래밍의 구성 요소

한빛미디어

|

2002-11-01

|

by HANBIT

12,522

저자: 마이크 빔(Mike Beam), 역 한빛리포터 왕수용

객체지향 프로그래밍은 Mac OS X 뿐만 아니라 최근 소프트웨어 개발의 초석이라고 할 수 있다. 객체지향 프로그래밍의 가장 근본적인 논리적 단위는 클래스로서 컴퓨터 내에서 하나의 특수한 목적을 수행하는 작은 프로그램이라 생각하면 된다. 그래서 프로그램을 만드는 것이란 바로 이 작은 클래스들을 서로 연결해 붙여서 좀더 복잡한 일을 수행하게 하는 것이라 보면 된다. 즉, 작은 것을 모으면 큰 일을 할 수 있다는 말이다.

클래스를 만들어서 하나의 프로그램을 만드는 것은 마치 초고층 빌딩을 만드는 것과 같다. 큰 초고층 빌딩을 만들기 위해 다양한 분야의 기술자들이 필요하듯이 이것도 마찬가지이다. 콘크리트를 다루는 사람, 전기 배선을 하는 사람, 배관 공사를 하는 사람, 통신 공사를 하는 사람, 그리고 이 모든 것을 조율하는 사람이 필요하다.

모든 일에는 먼저 그 일을 해 보았고, 또한 어떻게 해야하는지 정확히 알고 있는 바로 그 분야의 전문가가 있다. 그러나 단지 이들 전문가들만 모아놓는다고 해서 하나의 초고층 빌딩이 만들어 지는 것은 아니다. 만들려고 하는 그 빌딩에 대한 지식을 가지고 있는 사람, 그리고 이들 전문가를 지휘, 관리 감독할 사람이 필요하다. 이 감독관은 이들 전문가에게 각자가 할 일을 지정해 준다. 바로 이 객체지향 프로그래밍의 세계에서는 바로 응용 프로그램이 이 관리 감독관이 되는 것이다.

각각의 클래스는 각각의 특수한 목적을 위해 만들어 졌다. 특히, 코코아 프로그래밍을 위해서 애플은 정말 다양한 클래스들을 만들어 놓았다. 코코아의 각 클래스들은 각 목적에 해당하는 진정한 특급 기술자들이다. 예를 들어 배열 전문가, 스트링 전문가, 숫자 전문가들이 그들이다. 각각의 클래스들은 스스로 어떻게 버튼을 그려야 하는지, 윈도우를 그려야 하는지, 슬라이드를 그려야 하는지 잘 알고 있다. 그리고 각 클래스들은 프로그램 내에서 각자 어떠한 역할을 해야 하는지도 잘 알고 있다. 프로그래머는 단지 이 클래스들을 필요에 맞는 곳에 배치만 해주면 된다. 이러한 방법을 통해서 초고층 빌딩에 해당하는 아주 복잡한 프로그램을 아주 간단하게 만들 수 있다.

각 클래스들은 시키는 대로 수행하는 아주 성실한 전문가들이다. 단지 알아야 할 것은 이 전문가 클래스와 어떻게 대화를 해야 하는지와 그 전문가들이 어떻게 동작하는지 이다. 다시 말해 이들 클래스가 어떻게 만들어 졌고, 어떤 것을 수행할 수 있는지만 알면 된다는 것이다. 본 기사를 통해 객체지향 프로그래밍의 기본 개념을 이해하여 이들 전문가 클래스들을 좀더 능숙하게 다룰 수 있도록 해보겠다.

기본 원칙

위에서는 클래스가 객체지향 프로그래밍의 기본 단위라고 하였다. 클래스는 실행할 때마다 실제로 역할을 하는 객체를 만들어 내는 설계도 역할을 한다. 객체는 클래스를 형상화하여 실제 컴퓨터 메모리에 존재한다.

클래스는 데이터 구조와 그 데이터 구조를 변경하고 이용하는 많은 함수들을 실제 소스코드에서 정의한 것이다. 이 데이터 구조는 인스턴스(instance) 변수라 하고, 함수들은 메소드(method)라고 한다. 이러한 방법으로 객체는 인스턴스 변수가 주어지고 객체가 어떻게 동작하는지 결정지워 진다.

애플이 작성한 『Object-Oriented Programming and The Objective-C Language』 에 보면 객체지향 프로그래밍이 무엇인지 아주 잘 설명하고 있다. "객체지향 프로그래밍의 실체는 상태와 행동을 함께 묶는 것이다. 데이터와 그 데이터에 대한 처리 - 그것을 좀더 높은 개념으로 생각하면 하나의 객체이고 이것을 컴퓨터 언어로 표현하는 것이다."

메시지 전달

객체의 본질을 이해하려면 메소드와 데이터 전달을 이해해야 한다. 메소드는 객체 안에 있는 데이터를 보호하고 있는 포장으로 볼 수도 있다. 이러한 방법으로 프로그래밍을 하면 객체의 데이터보다는 객체가 수행 할 수 있는 역할에 초점이 맞추어 질 수 있다.

예를 들어 객체의 인스턴스 변수가 직접 다른 객체에 의해 조작되는 경우는 매우 드물다. 그 보다는 접근용 메소드(accessor method)를 이용해서 객체내의 데이터의 값을 얻어 오거나, 값을 변경할 수 있게 한다.

객체는 메시지를 보내면서 동작한다. 메시지는 그 메시지를 전달 받는 객체에게 그 객체의 해당 메소드를 실행함으로써 어떠한 작업을 수행하라고 하는 명령이다. 이러한 방법으로 복잡한 프로그램에서는 각 객체들이 서로가 서로에게 메시지(데이터 값을 얻는 메시지, 데이터 값을 변경하는 메시지, 어떠한 작업을 지시하는 메시지 등)를 보냄으로써 하나의 큰 작업을 수행한다.

하나의 프로그램은 프로그램이 갖는 궁극적인 목적을 위해 다양한 객체들이 서로 통신하는 커다란 객체의 네트워크라 생각할 수 있다. 같은 맥락으로, 각 객체를 클라이언트와 서버로 이해할 수도 있다. 클라이언트는 서버에게 어떠한 서비스를 요청하는 것이라고 이해할 수도 있다.


Learning Cocoa

참고 도서

Learning Cocoa
Apple Computer, Inc.




상속

객체지향 프로그래밍에서 가장 중요한 개념은 바로 상속이다. 상속의 개념은 이미 존재하는 클래스(상위 클래스)에서 기존의 것은 그대로 상속하면서 새로운 특성과 동작을 추가 또는 수정함으로써 새로운 클래스를 만드는 것이다. 이 상위 클래스를 슈퍼클래스(superclass)라 하고 새로 만들어진 클래스를 서브클래스(subclass)라 한다.

이러한 방식으로 서브클래스는 행동을 상속해 특화시키면서 상위 클래스를 좀더 세분화시킨다. 예를 들어 Appkit에서 NSButton은 NSControl 클래스의 서브클래스이다. 따라서 NSButton 클래스는 NSControl 클래스의 모든 기능과 내용을 그대로 가지고 있다.

상속으로 인해서 마치 나무의 뿌리와 같은, 클래스들의 거대한 계층적인 조직이 만들어진다. 가장 윗단에는 모든 클래스들의 공통 클래스가 있다. 파운데이션 프레임워크에는 코코아의 모든 클래스의 상위 클래스가 정의되어 있다. 이 클래스는 NSObject이다. 이 클래스는 모든 객체들이 기본적인 수행해야 할 내용들을 정의하고 있다.

상속은 많은 점에서 유용하다. 이것은 이미 테스트하고 검증된 소스를 재사용하기 때문에 새로운 버그가 발생할 가능성을 줄여준다. 그리고 상속은 객체지향 프로그래밍에서만 가능한 디자인 방법론을 제시해 준다.

만일 공통적으로 수행하는 부분이 많은 여러 개의 클래스들에 있다면 이 공통적인 부분을 뽑아내어서 하나의 슈퍼클래스를 만들고 다른 것들은 이 슈퍼클래스를 상속하는 클래스로 만들 수 있다. 이렇게 해서 공통적인 부분만 수정을 하면 이 공통부분을 상속하는 모든 부분에도 자동적으로 적용되므로 관리도 쉬워진다.

예를 들어 원, 사각형, 정사각형등을 다루는 그래픽 프로그램을 만든다고 생각하자. 이와 같이 모양을 다루는 그래픽 프로그램에서 모양을 다루는 클래스들은 실제 그 모양과 관계없는 부분을 제외하고는 많은 부분에서 공통점이 있다. 이러한 공통적인 부분은 나머지 클래스들의 슈퍼클래스인 Shape라는 클래스로 정의하고 Rectangle, Square, Circle 이 세 클래스는 위 슈퍼클래스를 상속해 각자의 특성에 맞는 부분만 수정하여 정의하면 된다. 이것이 바로 상속의 편리한 점이다.

상속의 또 다른 사용법은 상속될 클래스에서 각자에 맞게 사용될 다양한 메소드들을 정의만 해놓는 것이다. 실제로 이 메소드에서는 아무것도 없이 비어 있거나, 혹은 아주 일부분만 구현해 놓고 실제로 사용하려면 이것을 상속한 클래스에서 나머지를 구현해서 사용하도록 하는 것이다. 이것을 두고 프로토콜(protocol)이라 한다. († 역자 주: 실제 프로토콜의 정의와 조금 어긋나 있어 오해의 소지가 있다.)

Objective-C에는 특정한 클래스와 연관되어 있지 않는 좀더 정식의 프로토콜을 정의하는 방법이 있다. 마찬가지로 이러한 정식 프로토콜에는 이 프로토콜을 따르는(conform) 클래스들이 구현해야 하는 메소드들의 목록이 선언되어 있다. 코코아는 이러한 프로토콜을 많이 사용한다. 이와 관련된 내용은 앞으로도 계속 연재할 필자의 기사에서 설명할 것이다.

캡슐화

캡슐화는 클래스를 사용하는 사람으로부터 클래스 내부 정보를 숨기는 것을 말한다. 클래스의 내부 정보는 외부 인터페이스로 완전히 포장(혹은 캡슐화)하고, 두 개를 완전히 분리 시킨다. 이렇게 하면 다음과 같은 많은 장점이 있다.

첫째로, 코드 관리가 쉬워진다. 이 인터페이스는 클래스를 만든 개발자와 이 클래스를 이용해 프로그램을 만드는 개발자 사이의 일종의 계약서이다. 클래스 개발자는 어떠한 메소드를 제공할 것인지, 어떠한 기능을 수행할 것인지를 기술해 놓는다. 그러면 프로그램 개발자는 그 인터페이스에 맞게 그 클래스를 사용하면 되는 것이다. 이렇게 함으로써 클래스 개발자는 그 외부 인터페이스만 그대로 두고 내부 구현은 마음대로 바꿀 수 있고, 설령 내부 구현을 바꾸어도 그 클래스를 사용하는 프로그램에는 전혀 영향을 주지 않게 된다.

이 인터페이스와 구현의 분리에 관한 전통적인 예제는 전화기이다. 수년에 걸쳐 전화기는 수화기, 12개 버튼의 다이얼이라는 동일한 인터페이스를 유지해왔다. 그렇지만 전화기 회사는 이러한 인터페이스를 바꾸는 것이 아니라 내부적으로 전화기의 기능을 좀더 안정적이고 빠르게 수행하기 위해서 전화기의 기능을 개선시켜 왔다. 요점은 외부 인터페이는 절대 변하지 않는다는 것이다. 전화선이 모두 디지털이 바뀌어도 우리는 전화기 사용법을 다시 배울 필요가 없다. 클래스 사용법도 마찬가지이다. 일단 클래스 사용법을 익혀두면 클래스가 내부적으로 어떻게 변화더라도 상관이 없다.

다형성(Polymorphism)

마지막으로, 이 객체와 객체지향 프로그램이 구성된 이러한 방식이 얼마나 강력한 결과를 가져다 주는 지에 대해 이야기 해보겠다. 바로 다형성에 관한 것이다. 다형성이란 많은 클래스들이 같은 이름으로 다양한 메소드들을 구현할 수 있다는 것을 뜻한다.

여기서 명백하게 알 수 있는 이득은 개발자가 기본적인 기능을 사용하기 위해서 많은 메소드 이름을 외우지 않아도 된다는 것이다. 예를 들어 Appkit에는 많는 클래스들이 intValue, doubleValue, floatValue 와 같은 이름 메소드들을 다양한 클래스에서 구현하고 있다.

많은 객체가 같은 이름의 메소드를 구현하고 있기 때문에, 실행시 동적으로 메시지를 받을 객체를 선택할 수 있게 된다. 다시 그래픽 프로그램을 예를 들면 그 프로그램에서 오려두기와 붙이기를 구현하려고 한다. 만일 ‘오려두기’ 명령이 수행되었을 때, ‘오려두기’ 명령은 현재 화면에서 선택된 모양을 표현하는 객체로 메시지를 보낼 것이다.

여기서 중요한 것은 ‘선택된’ 이라는 것이다. 당연히 프로그램에서 미리 ‘오려두기’ 명령을 받을 객체를 선택해 놓을 수가 없을 것이다. 이 객체는 사용자가 화면에서 그 모양을 선택하면 그때 ‘선택’ 되는 것이고 그때 ‘선택’된 객체에 이 ‘오려두기’ 명령이 전달되는 것이다. 이것은 프로그램이 실행할 당시 사용자에 의해 동적으로 만들어지는 것이다. 이러한 것이 동작하기 위해서는 모든 화면상에서 나타나는 모양을 표현하는 객체는 모두 각자의 ‘오려두기’ 메소드를 구현해 놓아야 한다.

다음 기사에서는 본 기사에서 언급했던 이러한 객체지향 개념이 Objective-C에서는 어떻게 구현되는지에 대해 이야기 할 것이다. 그리고 실제 Objective-C의 코드는 어떻게 생겼는지도 살펴볼 것이다.
마이크 빔(Mike Beam)은 Geo Center Inc의 프로그래머이며 현재 오라일리 Cocoa 관련서를 집필중이다.
TAG :
댓글 입력
자료실

최근 본 상품0