Language/C++ 객체지향의 개념
  • 728x90
    반응형

     

     

    최근의 소프트웨어 개발 환경은 "객체지향(Object Oriented)"의 바람을 타고 있다. 객체지향 프로그래밍, 객체지향 모델링, 객체지향 방법론 등 소프트웨어와 관련된 여러 기술들이 객체지향과 음으로 양으로 관련을 맺고 있다. 앞으로 몇 개월간 객체지향과 관련된 여러 기술들을 차례로 연재함으로써 객체지향의 체계를 정리해 보고자 한다.

    앞으로 연재되는 모든 글은 아래 나열된 서적들과 컴퓨터 잡지 및 인터넷 상의 자료들을 재정리한 것임을 밝혀둔다.

    • Grady Booch, Object-Oriented Analysis And Design With Applications, Addison Wesley, 1994
    • Ivar Jacobson, Object-Oriented Software Engineering, Addison Wesley, 1994
    • Grady Booch, James Rumbaugh, Ivar Jacobson, The Unified Modeling Language User Guide, Addison Wesley, 1999
    • James Martin, James J. Odell, Object-Oriented Methods, Prentice-Hall, 1995
    • Martin Fowler, Kendall Scott, UML Distilled, Addison Wesley, 1997
    • 대림정보통신㈜ 컨설팅센터, 객체란 무엇인가, 전자신문사, 1997
    • 박현철, 객체지향 분석설계, 비앤씨, 1999
    • 윤정모, 한규정 역, 객체지향 시스템 개발, 동일출판사, 1996

     

     

    객체지향의 기원

    객체(object)의 개념이 처음 등장하는 것은 60년대 중반에 소개된 Simula라고하는 시뮬레이션 언어를 통해서이다. 그 이전에도 객체라는 용어는 인공지능 등 몇몇 분야에서 가끔 나타나기도 하였지만 "캡슐화(encapsulation)", "다형성(polymorphism)" 등 객체지향의 개념이 비로서 소개되었다.

    객체지향이란 용어가 중요하게 인식되기 시작한 것은 70년대 초반 XEROX사의 PARC(Palo Alto Research Center)에서 "Dynabook" 시스템을 개발하면서 소프트웨어로 Smalltalk을 만들었고, 여기에는 현재의 객체지향 개념의 상당수가 포함되어 있다.

    80년대 중반에 들어서는 객체지향 프로그래밍이 상당히 활발히 확산되었고 C++, Objective C, Eiffel, Ada95 등 수 많은 객체지향 언어들이 연이어 탄생하게 된다.

    객체지향 프로그래밍이 일반화되어가면서 설계와 분석, 방법론, Tool 등 여러 소프트웨어 개발 영역으로 객체지향을 확산하려는 시도가 90년대 초부터 일어났으며, 이에 따른 기술의 표준화도 함께 이루어져 갔다.

    최근에는 인터넷의 급격한 신장으로 Java 등 분산 컴퓨팅 환경에 맞는 객체지향 언어와 CORBA, DCOM 등 분산 객체 및 샌프란시스코(San Fransisco) 같은 기업 프레임워크의 보급 뿐만 아니라 메타 방법론이라 할 수 있는 UML(Unified Modeling Language)로의 표준화 작업까지 착실이 진행되고 있는 중이다.

     

     

     

    객체지향 등장의 배경

    객체지향의 패러다임(paradigm)이 인기를 얻게 된 배경은 그 전부터 존재해 오던 개발 방식에 뭔가 문제가 있었고 이를 객체지향 방식이 해결해 줄 수 있다는 실마리가 보이기 때문이다.

    프로그래밍과 분석/설계를 통틀어 소프트웨어의 개발 방식은 구조적이지 못한 방식에서 구조적인 방식으로, 구조적인 방식은 다시 프로세스를 우선적 분석하는 방식에서 데이터를 우선적으로 분석하는 방식으로 변천해왔다.

    70년대 이전 구조적이지 못한 개발 방식에서는 무계획적으로 하위 프로그램들을 개발하여 가면서 최종 시스템을 맞추어나가는 상향식(bottom-up)이었다. 그러다 보니, 프로그램들간의 연결이 어렵게 되고 모듈화가 되지 않으며 중복 코딩으로 조잡한 결과가 나올 수 밖에 없었다.

    구조적 개발 방식에서는 모듈화에 의한 코딩과 하향식(top-down)으로 SDLC(Software Development Life Cycle)의 전개를 따름으로써 계획적이 되고 분할과 정복(devide and conquer)의 원칙이 성립되었다. 즉, 소프트웨어를 모듈로 분할한 다음 공통 모듈과 모듈간 인터페이스를 계획하여 전체 시스템을 통합할 수 있게 된 것이다.

    이러한 구조적인 방식은 구조적 분석과 설계(structured analysis & design)로 상징되는 구조적 기법(structured technique)과 그 뒤에 나온 정보공학(information engineering)으로 발전하였다.

    이들이 바로 각각 프로세스 지향 방식과 데이터 지향 방식을 대표하는 개발 방식이다.

    구조적 기법에서는 프로세스들을 단위 모듈까지 분할해 내려가며 각 프로세스들의 흐름을 분석하고 여기서 프로세스간에 전달되는 데이터를 추가적으로 분석해낸다. 데이터베이스라는 개념도 없던 시절이므로 논리의 구성이 우선인 것은 당연할지 모른다. 이 방식에서는 프로세스의 분할과 흐름, 데이터의 흐름이 표현되는 DFD(Data Flow Diagram)를 중심 모델링 도구로 삼는다.

    정보공학은 구조적 기법의 대부분의 내용을 수용하고 있지만, 데이터 지향이라는 데 큰 차이점이 있다. 먼저 엔티티(entity)의 식별을 통하여 데이터의 관계와 구조를 명확히 한 다음 이러한 데이터 구조를 지원하는 프로세스를 설계한다. 이것은 컴퓨터 시스템의 고유한 데이터 구조를 안정적으로 만들면 업무 프로세스의 변화에도 프로그램 수정을 줄일 수 있다는 장점이 있다.

    프로세스 지향이나 데이터 지향 모두 프로세스와 데이터를 분리하는 철학을 가지고 있어, 분석 단계에서 발견한 것들을 설계 단계에서 기능으로 구현되도록 늦추어 놓는다. 따라서 분석 단계의 명세서에서 "무엇(what)"을 하는 것인가를 잘 정리해 놓고도 설계 단계에서 "어떻게(how)"하는 것인가로 변형시키는 데 어려움을 겪는다.

    또한 데이터와 프로세스의 분리는 인간이 사고하는 방식과는 차이가 있다. 즉, 인간은 사물과 그 사물의 행위를 묶어서 생각하지 따로 떼어 개별적으로 생각하지 않는다. 따라서 데이터와 프로세스가 분리된 기술적인 산출물은 비전문가가 보아서 쉽게 이해하기 힘들며, 때문에 개발자와 사용자간에 의사소통에도 어려움이 발생한다.

    객체지향 기법에서는 요구명세서에 존재하는 사실을 그대로 객체로 찾아 모델링을 한다. 이것은 곧바로 설계와 구현으로 이어진다. 데이터와 프로세스가 분리되지 않으므로 이들 사이의 연결고리도 필요 없고, 객체 내부에 어떤 데이터가 있고 어떤 프로세스로 어떻게 가공하는지 알 필요도 없다. 단지 무엇이 필요하면 다른 객체에 메시지만 전달하면 된다.

    이러한 사실은 개발도중에 개발방법의 전이가 이루어지지 않고 부드럽게 이어지며, 모델이 단순화해져 자연스럽게 여러 사람이 개발 작업에 참여할 수 있다는 장점이 있다.

     

     

     

    객체지향의 요소

    객체지향의 기본 사상은 복잡한 메커니즘의 현실 세계를 인간이 이해하는 방식으로 시스템에 적용시켜보자는 것이다. 이를 위해 객체지향 기술에는 객체(object)와 객체들의 범주를 나타내는 클래스(class), 그리고 객체간의 상호작용을 위한 메시지(message)를 기본 모형으로 제시하고 있다.

     

    🎯 객체

    객체(object)란 보고 만질 수 있는 것, 지성적으로 이해할 수 있는 것, 생각이나 행동이 추구하는 바를 말한다. 또는 문제영역에서 잘 정의된 역할을 갖고 있는 각각에 대해서 구별할 수 있는 품목(item), 단위(unit), 개체(entity)라 정의하기도 하며 단순히, 정의된 경계를 갖고 구별되는 어떤 것이라 말할 수도 있다.

    다시 말해서 객체는 학생, 교실, 책 같은 생각할 수 있는 모든 사물이나 공부, 수학 같은 개념상으로 존재하는 것 등 모든 것이 될 수 있다. 좀 더 구체적으로, 문제영역에 속한 사물 중에 관리의 필요성이 있거나 중요한 개념이라면 더 좋은 객체가 될 수 있다.

    시스템의 관점에서 본다면 어떤 상태(state)를 나타내는 데이터의 구조와 동작을 수행하는 연산(operation)으로 이루어진 프로그램의 한 요소이다. 여기서의 연산을 객체지향에선 메소드(method)라고 한다. 이렇게 객체의 상태는 데이터에 의해 결정되고 동작은 메소드에 의해 결정된다. 다음은 소프트웨어에서 객체가 어떻게 구성되고 연관되는지 보여주는 그림이다.

     

     

    소프트웨어의 객체

     

     

    🎯 메시지

    홀로 존재하는 객체는 아무런 의미가 없다. 대부분의 객체는 무언가를 실행하기 위해서 다른 객체를 필요로 한다. 예를 들어, 선생님은 학생과의 관계에서 존재의 의미가 있고 수업을 하고 평가를 하는 등의 상호작용을 일으킨다. 이러한 상호작용은 메시지(message)를 통해서 이루어진다.

     

    메시지는 세부분, 즉 메시지를 받는 수신자 객체(receiver)의 이름과 수신자가 수행할 메소드(method)의 이름, 메소드 수행시 전달되는 인자(argument)로 구성된다. 객체지향 프로그래밍에서 쓰는 용어인 메소드(method)는 메시지와 동의어이며 일반적으로 함수(function)와도 같은 개념이다.

     

    예를 들어 myCustomer라는 객체에게 메시지를 보내는 Java 문장에서, 

    myCustomer.addToOrder(itemNumber, price, quantity);

     

    수신자는 myCustomer, 메소드는 addToOrder, 인자는 itemNumber, price, quantity의 3개가 된다.

     

    🎯 클래스

    모든 객체는 반드시 클래스를 통해서만 정의될 수 있다. 클래스는 객체의 타입을 정의하는 템플릿(template)으로서, 여러 객체의 공통적인 속성(attribute)과 메소드(method)를 가지고 있는 클래스가 먼저 정의되면, 이 클래스를 통해서 다시 객체가 정의되는 것이다.

     

    이를 테면 회사라는 조직에는 많은 사원들이 있고, 이들 중에는 이과장도 있고 김대리도 있다고 하자.

    이들을 시스템으로 표현하려면 많은 공통적인 요소, 즉 속성들이 있는데, 성명, 사번, 부서, 급호 등이 그것이다. 급여계산이나 업무처리는 메소드가 될 것이다. 이러한 속성과 메소드를 가지는 사원은 클래스가 되고 이를 통해 이과장, 김대리 등의 객체가 만들어진다.

     

    이렇게 한 클래스에 속하는 각각의 객체를 그 클래스의 인스턴스(instance)라고 하고, 객체들의 유형이 되는 클래스를 객체의 타입(object type)이라고 한다.

     

     

    객체지향의 원리

    객체, 메시지, 클래스가 객체지향의 핵심요소이고 이러한 요소를 이용하여 객체지향의 원리를 이루어내는 요소가 있다면 추상화, 캡슐화, 상속성을 들 수 있다.

     

    🎯 추상화

    현실세계의 사실을 그대로 객체로 표현하기 보다는 문제의 중요한 측면을 주목하여 상세내역을 없애나가는 과정을 추상화(abstraction)라 한다. 객체지향에서는 클래스를 통해서 추상화를 지원하고 있으며, 이것은 다른 전통적 프로그래밍보다 강력한 추상화의 방법이다.

     

    추상화의 가장 기본적인 형태는 "프로세스 추상화(process abstraction)"이다. 프로그램에서 자주 나오는 상세한 부분을 함수로 묶어 호출하게 함으로써 이해하기 쉽고 간단한 모양으로 만들어 준다.

     

    다음의 Java 구문에서

    public static void printMessage() {
        System.out.println("Hellow, World!");
    }

     

    System.out.println("Hellow, World!"); 의 경우는 함수로 추상화된 가장 기본적인 예이다. println이라는 함수(메소드)는 문자열의 끝에 \n을 넣어 출력하는 동작을 수행하지만, 개발자는 내부적으로 그것이 어떻게 작동되는 것인지 상세 내역을 알 필요없고 단지 println에 출력하고자 하는 문자열을 괄호안에 넣어주면 그만이다.

     

    추상화의 또다른 축은 "데이터 추상화(data abstraction)"인데, 데이터 추상화의 가장 기본적인 형태는 integer, real, date 같은 데이터 타입이다. 개발자는 정수 연산의 값의 범위나 진법, 보수 형태의 치환 등을 일일이 프로그램해 넣을 필요없이 그저 선언만 해주면 된다. 또한 C에서는 typedef struct 같은 추상 데이터 타입, 사용자 정의 데이터 타입을 통해 데이터 구조를 원하는 데로 추상화하여 쓸 수 있다.

     

    그러나 이렇게 전통적 언어에서의 추상화 방식은 데이터와 프로세스를 별도로 추상화함으로써 추가적인 작업의 가능성이 많고 내부 메커니즘이 철저하게 숨겨지지 못하여 진정한 추상화라고 볼 수 없다.

     

    객체지향 언어에서는 클래스를 이용함으로써 데이터와 프로세스를 함께 추상화의 구조에 넣어 보다 완벽한 추상화를 실현한다.

     

     

    🎯 캡슐화

    객체의 상세한 내용을 객체 외부에 철저히 숨기고 단순히 메시지만으로 객체와의 상호작용을 하게 하는 것을 캡슐화(encapsulation)라고 하고 다른 말로 정보 은닉(information hiding)이라고 한다. 즉, 캡슐화는 추상화와 거의 같은 개념이지만 추상화를 지원하며 보다 구체적이고 제한적이다.

     

    예를 들면, 클래스를 선언하고 그 클래스를 구성하는 객체에 대하여 "public" 또는 "private" 등으로 정의해준다. 이렇게 되면 "public"으로 정의된 함수 또는 데이터는 외부에서 사용이 가능하며, "private"으로 선언된 경우는 외부에서 제어할 수 없고 내부에서만 사용된다.

     

    이것은 클래스 외부에는 제한된 접근 권한을 제공하며 원하지 않는 외부의 접근에 대해 내부를 보호하는 작용을 한다. 이렇게 함으로써 이들 부분이 프로그램의 다른 부분들에 영향을 미치지 않고 변경될 수 있다.

     

    🎯 상속성

    추상화는 복잡한 프로그램을 간단하게 해주고 분석의 초점을 명확히 할 수 있다. 캡슐화는 객체의 내부구조와 실체를 분리함으로써 내부의 변경이 소스 프로그램에 미치는 영향을 최소화한다. 따라서 유지보수도 용이해진다.

    상속성(inheritance)는 객체기술의 가장 핵심이 되는 개념으로 프로그램을 쉽게 확장할 수 있도록 해주는 강력한 수단이 된다. 앞의 두 개념은 객체지향이 아닌 개발 방법에서도 흉내를 낼 수 있으나 이것은 객체지향 언어와 개발 방법만의 특성이다.

     

    예를 들어, 어떤 회사에 근무하는 사원이 정규직 사원, 계약직 사원으로 구분된다고 하자. 이때 사원이라는 정보는 사원의 이름과 주소, 사원번호, 성별 등의 공통된 속성을 가지고 있다. 정규직 사원은 호봉과 연봉을, 계약직 사원은 계약기간과 시간급 같은 고유의 속성들을 가지게 된다. 물론 정규직 사원과 계약직 사원은 모두 사원이라는 클래스의 속성을 그대로 물려받는다. 여기에 추가하여 고유의 속성을 정의하게 되는 것이다. 사원은 클래스 계층에서보면 수퍼클래스(super class)가 되고 정규직과 계약직은 서브클래스(sub class)가 된다. 이렇게 수퍼클래스와 서브클래스간의 관계가 객체지향의 상속성의 개념이다.

     

    상속의 효과는 클래스를 체계화할 수 있으며, 기존의 클래스로부터 확장이 용이하다는 것이다. 함수와 변수를 서브클래스에서는 따로 정의하지 않고 상위의 클래스의 내용에다 추가적인 특성을 덧붙이기만 하면 되므로 매우 효율적이다. 또한 공통의 특성을 서브클래스마다 반복적으로 기술하지 않고 한번만 기술하기 때문에 중복을 줄여 준다.

     

     

     

     

     

    728x90
    반응형
상단으로