오랫만에 찾아뵙네요 :) 허접(?)한 강의 보아주셔서 감사하고 있습니다.
이번에도 동영상으로 하려다가, 동영상으로 하니 말이 정리가 좀 안되는 경향이 있어서, 그리고 이번에 이야기할 OOP내용은 사실 동영상보다는 글이 더 좋다고 생각되어 글로 남겨볼까합니다.
지난번과 마찬가지로 기본적인 내용입니다. 하지만 이번강의에서는 OOP내용을 설명하면서 Objective C 의 문법 몇가지를 이야기 할 것이므로 OOP에 친숙하신 분이라도 objective C를 처음 접하시는 분이시라면 한번 읽어보시길 권장합니다.
C++ 나 Java를 하시는분은 너무나도 잘 알고있는 부분이라 생각하지만 일단은 처음접하는 분을 기준으로 이야기하겠습니다.
지난시간에 첫강의에서 hello world 프로그램을 만들어보았습니다. C 에서도 만들어보았구요, objective C에서도 만들어보았는데요. C언어와 objective C의 차이가 무엇을까요? printf 와 NSLog 의 차이처럼 쓸수 있는 풍부한 kit들의 차이일뿐일까요? 사실 사용할수 있는 함수나 그러한 kit들은 C가 더 많을껍니다. 더 많은 기술들이 있을것이구요. (C가 가장 대중적으로 사용되기 때문이지요. 여기에는 한가지 어패가 있을 수 있지만 실제 그렇다고 볼수도 있지 않겠습니까?! :) 그렇다면 차이가 무엇일까요? 바로 OOP입니다.
OOP는 Object Oriented programming의 약자입니다. 번역하자면 객체지향 프로그래밍 이지요. 설명을 시작하게전에 이번강의에서는 새로운 용어들이 많이 나올것입니다. 실제로 Standford University에서 제공하는 iPhone programming 강의에서도 OOP 용어 라고 해서 강의가 따로있을정도입니다. 그러니 그냥 부담없이 받아들이시면 되겠습니다.
객체지향 프로그래밍은 프로그램제작을 아주 간결하게 만들어주는 하나의 방법입니다. 프로그래밍 뿐만아니라 프로그램에 대한 유지보수도 매우 쉽게 만들어주는 일종의 프로그래밍 스타일이라고 생각하시면 될것 같습니다. 우리가 이야기하고 있는 Objective C는 이름에서도 느껴지듯 이러한 OOP를 기반으로 정교하게(?) 설계되어진 언어이고 우리는 이것으로 재미있게(?!) 프로그래밍을 할수 있을꺼라 믿습니다(제발!)
자 그런데 아직 제가 OOP가 뭔지는 한마디도 하지 않았습니다. 아마 이 개념에 대해 잘 모르시는분은 뭔가 좋은것 같긴 한데 무슨말인지 모르겠다 하실것인데요. OOP 개념에 대해 정리해놓은 정말 훌륭한 문서가 있어 그 설명으로 대신하고자 합니다. 제가 사랑하는(?!) (왜냐면 과제할때 정말 훌륭한 도움이 되었던 사이트입니다. ) JOINC WIKI 의 OOP설명을 대신합니다.
OOP를 아시는분은 넘어가셔도 좋습니다만, 그게 아니라면 반드시 한번 읽고넘어가시길 권합니다. 글이 약간 오래되어 잘 안읽힐수도 있는데, 여튼 꼭 한번 읽어보세요 :)
출처 : http://www.joinc.co.kr/modules/moniwiki/wiki.php/Site/SoftWare_engineering/OOP
- C프로그래머를 위한 C++에 내용을 덧붙이는 것도 좋을것 같군요. 작업을 함 해볼까나 -.-;
1 문서정보
1.1 작성자 정보
- 최초 작성자: mwyun(멍)
- 이래저래 수정한 사람 : yundream
2 객체지향
어디에선가
OO에 대응되어서 사용되는
객체지향자체가 잘못된 번역의 결과물이란걸 읽은 기억이 있다. 그러나 이게 번역이 잘못되든 되지 않았던간에 의미를 전달하는데 별 지장이 없고, 현재 표준적인 용어로 사용하고 있으므로
객체지향이라는 단어를 그대로 사용하도록 하겠다.
2.1 컴퓨터라는 기계
최초의 근대적 기계의 개념을 담고 있는 기계의 제작은 아마도 고대 그리스시대로 올라갈듯 하다. 아리스토텔레스는 전쟁에서 사용될 수 있는 기계를 만들었으며, 실제 전차(현대적 개념의 탱크)도 설계했던 것으로 알려진다.
이후에 만들어진 기계는 뭐 사실은 고만고만한 기계였는데 이들 기계는 주로 물리력을 이용해서 "물건을" 옮기는 일을 하였다.
바퀴와 기어들로 이루어져 있으며 제어하기 위해서 인간이나 동물의 물리력을 필요로 했으며 얼마나 많은 일을 할 수 있는지를
나타내는 단위로 '
마력을
사용했다. 마샬 맥루한이 지적했던 것처럼 기계라는 것은 인간의 신체의 기능을 외부로 확장하는 장치다. 컴퓨터가 나타나기 전까지의
기계들은 인간신체의 말단에 위치해서 주로 근육에 의해서 제어되는 신체를 확장시키는 용도로 만들어졌다. 바퀴, 지레, 망원경,
수레, 각종 공구들이 그것이다.
인간의 신체의 기능을 확장시키려는 시도는 인간의 뇌의 기능을 확장시키려는 시도로도 이루어진다. 기억하고 추론하는 기능이 그것이다. 물론 당시의 기술적인 한계 때문에 이러한 시도가 결실을 맺지는 못했다. 비교적 단순하다고 생각되는
아날로그 계산기와 그 응용정도로 만족해야 했다.
그러다가
컴퓨터라
는 기존의 기계의 개념과는 매우 다른 기계가 만들어진다. 이 기계는 인간의 뇌의 기능을 확장시키려고 한다는 점에서, 기어를
통해서 작동하는 아날로그 계산기와 기본적인 목적에 있어서 같다고 할 수 있다. 그러나 기존의 계산기와 다른 근본적인 차이점을
가지고 있었다. 바로 전기와 전자를 이용해서 작동한다는 점이였다. 아날로그 장비로 인간의 뇌를 확장시키는데 있어서 가장큰
어려움은 아날로그 장비의 핵심인 기어의 크기와 기어들을 이루고 있는 금속의 특징이였다. 기어는 크기가 컸으며 녹이 쓸고 잘
마모가 되었으며, 쉽게 고장이 났다. 복잡한 기계를 만들려고 한다면 수천 혹은 수만개의 기어와 태엽이 필요했다. 게다가 느리기
까지 했다. 또한 한번 만들어지면, 그 기능을 바꾸기가 쉽지 않았다. 이들 계산기는 기어와 태엽의 물리적인 배치가 소프트웨어의
역할을 했다. 즉 하드웨어만 있었지 소프트웨어는 없었다. 범용으로 사용할 수 있는 기계를 만들기가 매우 힘들었다는 얘기다.
반면 전기와 전자로 작동하는 기어와 태엽에 비해서 그 속도가 비교자체를 할 수 없을 정도로 빨랐다. 물리적인 제약에서도 비교적 자유로울 수 있었다. 또한 컴퓨터는 소프트웨어와 하드웨어를 분리할 수 있었는데, 이는
범용추론기계를 만들 수 있는 길을 열어 놓았다.
컴퓨터는 정보를 처리함에 있어서 획기적인 기계이긴 했지만 아날로그 기계와는 달리 상태가
참과
거짓으로 표현되는 한계를 가지고 있었다.
참과,
거짓으로 정보분석이 진행되는 논리연산에는 효율적이였지만 아날로그 적인 실세계의 다른 정보들을 처리하기에는 그다지 효율적이지 못하다. 초기에는 컴퓨터의 사용용도가 한정적이였으므로
참,
거짓을 잘 이용하는 정도로 대부분의 일을 처리할 수 있었다. 프로그래밍언어 역시 이러하였다. 기계어, 어셈블리어, C(이론이 있을 수 있겠다) 등이 그러한 부류에 속한다.
참과
거짓에 기초를 둔 논리연산은 어떤 일련의 순서를 따르면서
정보를 처리하도록 되어 있다. 컨테이너 벨트를 이용해서 물건을 처리하는 것으로 보면 될 것이다. 컨테이너 벨트는 물건과 물건을
처리하는 프로세스가 분리되어 있는데, 컴퓨터 역시
데이터와
데이터를 처리하는 방법이
분리되어 있다. 이러한 방식은 복잡하지않은 정보를 처리할때는 효율적이지만 가계/기업경영/문서작성/음악재성/공장제어/게임에서와
같이 정보와 정보가 상호연관되어서 복잡하게 얽혀있는 경우에는 효율이 극히 떨어지게 된다. 수백개의 컨테이너 벨트가 만들어져
있는데, 필요에 따라서 이들 각 컨테이너를 서로 연결시켜서 데이터를 처리해야할 경우를 생각해보면 될것이다. 입력과 출력이 매우
명확한 제조업에서야 컨테이너벨트를 재배열해야 하는 일이 그다지 필요 없겠지만 소프트웨어 개발영역은 그렇지 않다. 따라서
소프트웨어를 개발하고 유지하고 보수하는데 많은 비용이 들게 된다.
그래서 만들어진게 "객체지향 프로그래밍"으로 컴퓨터가 데이터와 데이터의 처리과정을 분리시켜서 생각하는걸 하나의 객체로 보고 처리하도록 만들어진 방법론이다. 이 방법론을 이용해서 코드의 재사용성, 유지/보수성을 높이고자 하게 된다.
간단히 말하자면 객체는 주변에서 볼 수 있는 모든 (관찰되어지는)사물이다. 삽살개, 호랑이, 세포, 사람.. 전부다 객체다.
또한 눈에 보이는 구체적인 것 뿐만 아니라 경제, 국가, 시장 같은 눈에 보이지 않는 것도 객체라고 한다.
모든 것이 객체다!!! 단순명료하긴 하지만 너무 포괄적인 것 같으니 객체의 특징에 대해서 정리해볼 필요가 있을 것 같다.
객체는 내면과 내면을 감싸는 외피를 가진다. 세포라는 객체는 세포내용물질과 이들을 감싸는 외피로 구성이 된다. 관찰자에게 보이는
것은 외피가 된다. 내용물들과 내용물들이 상호작용하는 과정은 관찰자에게 감추어진다. 이렇게 내면을 감추는 외피를 가지는 것을 추상이라고 하는데, 이 추상은 객체가 가지는 대표적인 특징이다. 여기에 따르면 외피를 가지지 않는 것은 객체라고 할 수가 없다. 외피가 중요한 이유는 주변의 다른 사물과 구분되는 표면이 있어야 관찰자에게 독립적인 사물로 보여질 수 있기 때문이다. 표면은 경계라고 해도 좋을 것이다.
경제나 국가와 같은 것들도 인간은 객체라고 본다. 물리적인 외피를 가지지 않지만 인간의 인식하에서 경제는 경계를 가지고 있기
때문이다. 경계를 가지고 있으므로 관찰자인 인간은 경제를 관찰하고 분석할 수 있다. 여기에서 어떤 대상이 객체로 보이느냐 아니냐 하는 것은 상대적일 수 있음을 알 수 있다. 경제관념이 없는 지역의 사람들에게는 경제는 관찰할 수 있는 대상이 아니기 때문이다.
객체는 객체를 포함할 수 있다. 치아와나 셰퍼드는 객체다. 여기에서 더 나아가 이들 치아와나 셰퍼드를 통칭하는 개도 객체가 될 수 있다. 개는 치아와와 셰퍼드와 같은 객체의 공통적인 특징을 분석해서 인간의 지성이 만들어낸 가상의 개념이지만 고양이라는 다른 개념과 구분되는 외피를 가지고 있으므로 객체라고 할 수 있다. 개라는 객체는 치아와, 셰퍼드 객체를 포함한다. 이러한 객체의 속성을 이용하면 객체의 계층적- Hierarchy - 구조를 만들 수 있다. 이것은 복잡한 자연현상을 단순화 시켜서 인식할 수 있도록 도와준다. 대표적인 예가 종,속,과,목,강,문,계일 것이다.
객체는 주변환경 혹은 다른 객체와 상호작용한다. 생물의 경우 상호작용은 감각기관을 통해서 내부로 정보를 받아들인 다음 이를
처리하고 운동기관을 통해서 다른 객체를 조작한는 형식으로 이루어진다. 개가 위협적으로 달려들면 눈으로 이 정보를 받아들여서
처리한다음 다리근육을 움직여서 달아나거나 혹은 온몸을 이용해서 싸우거나 하는 식이다. 이러한 상호작용은
경제와 같은 구체적인 형태를 가지지 않은 객체에도 적용된다. 경제의 경우에는
신문,
뉴스,
주식매입,
은행업무등을 통해서 상호작용할 것이다.
이상에서 객체의 다음과 같은 특징을 뽑아낼 수 있을 것 이다.
- 객체는 내면과 내면을 감싸는 외피를 가진다.
- 내면은 외피 내부로 숨겨지며 이를 추상이라고 한다.
- 객체는 외피를 가짐으로써 주변사물과 독립적으로 구분될 수 있다.
- 객체는 외피를 가짐으로써 관찰대상이 될 수 있다.
- 구체적인 형태를 가지지 않는 것들 - 경제, 국가 - 도 객체가 될 수 있다.
- 객체에 대한 정의는 상대적이다.
- 객체는 객체를 포함할 수 있다.
위의 객체에 대한 내용은 다분히 철학적, 다른말로 말장난으로 보일 수 있을 것 같다. 그러나 이러한 특징은 컴퓨터 영역에서의 Object-orinted Programming 에도 그대로 나타난다.
아리스토텔레스가 추상적인 분류체계를 구축할 수 있었던데에는 동물에 대한 다양성과 그 기능에 대해서 특히 관심이 많았기 때문이다.
이들을 관찰하기 위해서는 그 다양함안에서도 공통되는 속성이나 행동약식 등을 찾아서 체계적으로 분류할 필요가 있었기 때문이다.
이러한 고찰의 결과는 “the class of fishes and the class of birds”이라는 그의 생각에
요약되어서 나타난다.
여기에서 fishes는 class다. 농어,빙어,붕어와 같은 객체들로 부터 공통의 속성을 뽑아내어서 만들어놓은 추상객체다.
이렇게 fishes라는 클래스를 만들어 놓으면, 이제 새로운 생물이 발견되더라도 fishes라고 부를 것인지 말것인지를 쉽게
결정할 수 있다. 새로 발견된 생물이 fishes라는 클래스가 가지고 있는 속성과 행동양식에 맞는지를 검토하면 되기 때문이다.
즉 class는 객체의 공통적인 속성과 행동양식- 메서드 -을 정의해 놓은
추상객체로 정의 내릴 수 있다.
class는 상위의 class를 가질 수 있다.
개 < 포유류 < 생물 이런 식이다. class는 객체가 될 수 있고, 객체가 클래스가 될 수 있다. 일반적으로는 속성과 행동양식이 실체된 경우를
객체라고 하고 그렇지 않고 속성과 행동양식을 단지 정의만 하고 있는
추상객체를
class라고 한다. 구체적인 실체를 가지지 않는
개는 class 이고,
개의 속성과 행동양식을 가진 실체하는
치아와,
삽살개를 객체로 보는 식이다.
분류체계로 볼때 객체는 class에 하위분류가 된다.class의 속성과 행도양식을 상속받아야 하기 때문이다. 때문에
치아와는 개다라는 명제는 성립하지만
개는 치아와다라는 역은 성립하지 않는다.
객체는 내면이 외피에 의해서 감추어진다고 했다. 환경과 상호작용하기 위해서는 환경이 내면으로 전달되어야 한다. 이때 문제가 되는 것은 외피에 의해서 내면과 환경이 단절되어 있다는 점이다.
Interface는 환경의 변화를 내면으로 전달하는 역할을 하는
장치다. 인간을 예로 들자면,
눈,
귀,
코,
입 등이 Interface로 이것을 이용해서 외부환경과 상호작용하게 된다.
가시광선을 눈으로 받아들여서 시신경을 통해서 내면에 있는 뇌로 전달해서 해석하고, 해석된 결과에 따라서 반응하는 식이다.
자동차의 Interface 는
핸들,브레이크,악셀레이터등이 될 것이다.
모든 사물을 객체로 바라보는 주의는
실증주의와
경험주의에 바탕한 현대적인 과학의 바탕이 된다. 즉 인간의 오감과
상호작용해서 분석되어진 정보를 오랜시간 분석해서 - 즉 경험을 통하여 - 보편적인 지식으로 만드는 과학적사고 방식 만들어냈다.
과학적 사고는 상호작용 가능한 객체를 대상으로 이루어진다. 이런 의미에서 종교는 과학과 다른 길을 가게 된다. 신과 상호작용할
수는 없는 노릇이기 때문이다. 상호작용할 수 없는 건 객체가 아니다. 언젠가 신과 제대로 상호작용할 수 있는 어떠한 방법을
찾아낸다면 종교도 과학이 될 수는 있겠지만 말이다. 아 물론 지금도 신도들은 기도를 통해서 신과 상호작용 한다고 하지만
상호작용의 결과를 보여주지 않으니, 분석불가가 된다. 입력은 있는데 출력은 없는 상태라고나 할까.
신을 직접 입증하는게 불가능하다고 생각이 되자, 그들의 성서에 적혀있는 신화적 내용이 신화가 아닌 사실임을 증명하는 것으로 신이
있음을 간접적으로 증명하고자 하는 시도가 있었다. 신화는 어떤 부족의 역사를 담고 있는 경우가 많고, 역사는 과학적 탐구가
가능한 영역이니 말이다. 이것을
창조과학이라고 한다.
그러나
창조과학이 의미가 있을지에 대해서는 회의적이다. 설사 역사적 사실이 입증되더라도
말이다. 신화속의 도시로만 알려졌던 트로이가 발견이 되고, 아킬레우스가 실제 존재하던 인물이였음이 증명되었다고 해서,
아킬레우스가 신의 아들이고 트로이 전쟁을 신들이 배후조정했다는 증거가 되는건 전혀 아니기 때문이다. 종교는 그냥 믿음의 영역으로
두면 되는 것이다.
때때로 기술이 발전함에 따라서 너무터무니 없어서
신화와 같은 것으로 생각되던게 상호작용 가능한 과학적 탐구가능한
객체가
되기도 한다. 4차원이네 10차원이네 하는 것들은 과거에는 터무니 없는 것이였으나 입자가속기의 등장으로 그 실체를 거의 규명할
수 있게 된게 그 예가 될 것이다. 그렇다고 해서 신과 대화가능한 기계를 만들어 낼 수 있을까 ?? 뭐, 이벤트호라이즌호는
강력한 중력발생기를 이용해서 뜬금없는 지옥도 다녀오긴 했지만 이건 어디까지나 영화의 이야기고.
2.3 추상(抽象)화 와 추상화 과정
위에서 객체는 내부를 숨기는 외피를 가진다고 했다. 이것을 추상이라고 하는데, 객체의 가장 큰 특징중 하나다. 이 추상에 대해서 알아보도록 하자.
현대적인 추상개념을 체계화 한것은
플라톤으로 생각된다. 플라톤은
이데아라는 것을 주창하였다. 세상은 이데아라는 완전한 세계에 있는 원본틀의 그림자로 생겨난 것이다라는게
이데아의 핵심이다. 원본의 그림자이니 세상은 언제나 불완전할 수 밖에 없다. 이데아는 완전한세계, 영혼으로 볼 수 있는 세계라는게 플라톤의 생각이었다.
개를 예로 들어보자.
개를 본적이 있는가 ? 뜬금없는 말 같지만
개그 자체를 본적은 없을 것이다. 왜냐하면
개는 물리적인 대상을 가리키는게 아니기 때문이다. 우리는 삽살개, 치아와, 셰퍼드를 볼 수 있지만
개를 본적은 없다. 플라톤이 주장하는 바에 따르면
개가 바로 치아와 삽살개 셰퍼드등 이 세계에 존재하는 여러가지 개의 성질을 가지는 것들의
유일한 원본이다. 이 유일한
개의 그림자가 바로 우리가 볼수 있는 치아와 인 것이다. 이데아는 우리가 사는 세계보다 차원이 높은 세계이므로 우리는 단지
개의 그림자만을 볼 수 있을 뿐이다.
이처럼 차원이 낮아지면 얻을 수 있는 장점이 있다. 그것은 수많은
개의 성질을 가지는 객체를 만들어 낼 수 있다는 점이다. 앞서 이 세상에 물리적으로 존재하는 개들은 이데아
개의 그림자라고 했는데, 그림자는 그 모습이 완벽하지 못하다. 광원의 거리와 흔들림에 따라서 찌그러지기도 하고 커지거나 작아지거나 할 수 있다.
개는 하나이지만 수많은 개들이 존재하는 이유이다.
플라톤이 이데아를 생각해 냈던 것을 반대로 하면 그게
추상화가 된다. 즉
멍멍 소리를 내고, 꼬리를 흔들며, 다리가 4개고, 코가 뾰족한 특징을 가지는동물들을
개라고
정의 하는 것이다. 이렇게 해서 우리는 눈에 보이지 않는
개라는 새로운 상위 차원의 개념을 만들어내게 되었다.
추상화 과정이란 어떤 구체적인 사물로 부터 공통적인
속성을 찾아내어서 그것들을 포괄할 수 있는 상위의
포괄적 개념을 만들어내는 과정이다.
2.4 컴퓨터에서의 추상화
컴퓨터 언어역시 이러한 추상화 과정을 거친다. 가장 간단한 어셈블리는 이를테면 생명체의 바이러스라고 할만한데, 가장 간단한
추상화 과정을 거친다. 기계어와 거의 일대일 대응을 하는데, 다만 좀더 이해하기 쉽게 만들도록 "한단계"의 추상화 과정을 거쳤을
뿐이다. 포트란, 베이직,
C와 같은 언어들은
어셈블리어에 비해서 더욱 많은 추상화를 이루고 있으며, 여러가지 면에서 크게 발전되었다.
그러나 이들 언어는 컴퓨터 기계가 만들어 졌던때의 그철학을 그대로 따르고 있어서 실제 생활에서 발생할 수 있는 다양한 문제를
푸는데 있어서 절차지향적인 방법을 따른다. 이건 어셈블리어 뿐만아니라, 포트란, 베이직, C 모두에 포함된다. 절차지향적이란
컨테이너 벨트라고 생각하면 된다. 재료를 집어 넣고 컨테이너 벨트에 집어 넣으면 최종적으로 물건이 튀어 나오는 것이다. 풀어야할
문제가 복잡해 질 수록 이런 절차지향적 방법으로는 한계에 부딪히게 된다. 즉 개발모델이 문제다.
여기에서 한계란.. 문제를 풀 수 없다라는 것이 아니고, 효율적으로 풀수 없으며
단지 푸는 것 뿐만 아니라, 유지하고 보수하고 확장시키는데 기존 방법으로는
많은 시간과 비용이 소비될 확률이 많다는 것이다.
그래서 만들어진 개발 모델이
객체지향 모델이다. 컨테이너 벨트 모형을 따르는 절차지향 개발 모델에서는 데이터와 데이터를 가공하기 위한 메서드(함수)가 서로 분리 되어 있다. 데이터가 계속 흘러가고 중간에 함수가 있어서 가공하고 다시 다음 함수로 넘겨주는 방식이다.
반면 객체지향 개발 모델에서는 데이터와 메서드를 분리하지 않고 하나의 공간에 둔다.
객체지향을 목표로 제작된 최초의 (성공적인) 언어로 Smalltalk라는 언어가 있다. Java도 이 언어를 기초래 햇 만들어
졌는데, 객체지향을 위한 기본적인 노선이 정립된 언어다. 객제지향 언어라고 한다면 보통 아래의 5가지의 요소를 만족시키는 특성을
지원할 수 있어야 한다.
- 모든 것은 객체다 : 간단하게 생각해서 객체는 데이터와 데이터를 처리하기 위한 메서드를 함께 가지는 모든 것을 말한다. 이론적으로 객체를 이용하면 모든 사물을 완벽하게 구현할 수 있다. (자동차, 개, 건물, 은행 서비스 ..)
- 프로그램은 객체사이의 메시지 전달을 이용해서 통신한다 : 두명의 사람(객체)가
상호작용하기 위해서 대화를 하는 것과 마찬가지다. 프로그램의 경우 두개의 객체(보통 클래스, 패키지라고 한다)를 연결하기 위한
메시지 전달 클래스를 만들 수도 있을 것이다. 사람과 사람이 대화를 하는데 중간에 매질(공기)이라는 객체가 대화를 전송하는 것과
같은 이치다.
- 각각의 객체는 자신만의 메모리를 가진다 : 객체는 데이터와 메서드를 하나의 공간에서 다루며, 객체는 다른 객체와 독립적으로 행동한다. 고로 자신만의 데이터를 저장하기 위한 공간을 가질 수 있어야 한다.
- 모든 객체는 이름을 가진다 : 각 객체는 독립적으로 구분될 수 있어야 한다. 그러기 위해서 이름(type)을 부여한다. 각각의 사람을 구별하기 위해서 "이름"을 부여하는 것과 마찬가지다.
- 동일한 특성의 객체는 동일한 메시지를 사용한다 : A라는 사람과 B라는 사람은 독립적인
객체이지만, 또한 "사람"이라는 동일한 특성의 객체이기도 하다. 이들 객체간의 대화를 위해서는 당연하지만 같은 언어가 사용되어야
할 것이다. 사람과 개의 경우에는 대화가 되지 않을 것이다. 프로그램에서도 동일한 특성의 객체들은 동일한 메시지를 이용해야
한다.
2.5 추상화를 통해 얻는 이득
자동차를 생각해보자. 자동차는 인류가 개발한 육상이동 수단중 가장 고도로 추상화된 기계다. 자체에 발전,공급,저장,통신,제어 시설을 갖춘 소형 공장이라고 할만하다.
그러나 운전자가 이러한 모든내용을 알아야지만 자동차를 이용할 수 있는 건 아니다. 대부분의 기능들은 추상화(숨겨져)있으며, 사용자는 단지 핸들과, 브레이크, 악셀레이터와 몇개의 계기판을 볼수 있으면 운전이 가능하다.
복잡한 내부 구현을 숨김으로써 사용자는 이것 저것 신경쓸 필요 없이, 제공되는 몇개의 인터페이스만으로 사용이 가능하다. 이게 추상화가 가져다 주는 첫번째 이득이다.
자동차가 처음 나왔던게 19세기 말이였던 것 같다. 그러나 성능상의 차이는 있겠지만 100년이 지난 지금도 자동차의 기본적인
운전방법은 거의 변함이 없다. 그때나 지금이나 여전히 운전자는 핸들, 브레이크, 악셀레이터 이 3가지를 이용해서 자동차를
제어한다. 이러한것 자동차의 구현을 "추상화"함으로 가능하다.
즉 구현과 인터페이스를 분리시켜줌으로 (최초에 인터페이스만 잘 설계한다면)기능이 대폭업그레이드 되더라도 사용자는 이것에 신경쓸필요 없이 기존의 운전기술을 그대로 사용할 수 있게 된다.
프로그램개발에 있어서도 이러한 이득을 그대로 이용할 수 있다. 추상화를(잘) 시키게 되면 인터페이스와 구현을 구분시켜 줌으로써
일반 프로그램개발을 할적에 세부저인 복잡한 구조를 신경쓸 필요 없이 제공되는 몇개의 인터페이스만을 이용해서 필요한 일을 할 수
있다. 구현을 업그레이드 시켜야할 경우에도 개발자는 여기에 대해서 신경쓸 필요가 없게 된다.
간단하게 생각하자면 우리가 프로그래밍을 위해서 사용하는
open(2),
write(2)같은 함수역시 추상화의 결과물이다. 우리는
open(2)의 내부구조가 어떻게 되어있는지 신경쓰지 않고도 잘 쓸 수 있다.
2.6 객체는 인터페이스를 가진다.
객체에 대해서 깊은 사고를 한 최초의 철학자는 (보통)아리스토 텔레스로 알려져 있다.그는 "the class of fishes
and the class of birds"라고 실존하는 모든 것들을 객체로 분류했다. 객체는 일반적으로 유일하며, 각 객체는
고유의 특징과 행동특징을 가지는 것으로 정의할 수 있다. 클래스란 이러한 객체의 고유 특성과 행동특징을 함께 묶어놓은 개념이다.
하나의 클래스는 여러개의 객체를 포함할 수도 있다. 새라는 클래스에 참새 1, 참새 2, 제비, 할미새와 같은 객체가 포함될 수
있는 것과 마찬가지다.
클래스(class)를 처음 도입한 객체지향 언어는 Simula-67 이다.
Simula는 그 이름에서 느낄 수 있는것 처럼 어떤 상황을 "시뮬레이션"하기 위한 용도로 작성되었으며
bank teller problem과 같은 문제를 해결하기 위해서 사용되었다. 여기에
상담원,
고객,
트랜잭션,
계정,
돈등과 같은 많은 요소들이 있다. 이러한 요소들은 "은행업무"라는 작업을 달성하기 위해서 상호통신하면서 일종의
그룹처
럼 움직인다. 그렇다면 이들 요소를 하나의 클래스로 묶어서 처리하게 된다면 좀더 현실에 가깝게 상황을 시뮬레이션 할 수 있을
것이다. 즉 요소의 유기적인 모임인 클래스가 또하나의 데이터가 되는 것이다. 각 요소는 하나의 클래스 안에서 유지적으로
움직인다. 예를 들어 고객은 상담원과 상담을 하고 자신의 계정을 통해서 저금을 하거나 돈을 찾거나 또는 다른일을 할 수 있다.
만약 새로운 고객이 은행창구에 들어온다면 새로운 "은행업무-1" 객체가 생성될 것이다.
이처럼 클래스라는 개념은 어떤 상황을 시뮬레이션 하기에 적당한 개념이라는 것을 알 수 있다. 이론적으로 클래스를 이용하면 모든
상황에 대한 시뮬레이션이 가능하다. 클래스에 있는 각각의 요소들은 어떤 문제를 풀기 위해서 존재한다. 즉 객체지향 프로그래밍이라
함은 어떠한 동일 문제해결영역에 있는 여러 요소들을 제어함으로써 문제를 해결하기 위한 개발철학이라고 할 수 있다. 대부분의
객체지향 언어에서 문제해결영역은 보통 class라는 키워드로 표현된다.
지금까지 클래스에 대한 대략적인 내용을 살펴보았는데, 지극히 추상적이고 철학적이라서 어떻게 써먹을 수 있을지 감이 잡히지 않을 수 있을 것 같다. 구체적인 이해를 돕기 위해서
전구에 대한 제어를 시뮬레이션 해보기로 하겠다. 문제영역은 빛의 조절이며 이 문제를 해결하기 위해서
켜기,
끄기,
밝게하기,
어둡게 하기라는 인터페이스 들이 필요함을 알 수 있다. 이들 인터페이스를 통해서 다루는 요소(데이터)는
빛이 될 것이다.
위의 클래스를 보면
빛을 조절하기 위해서 4개의 인터페이스가 사용자(프로그래머)에게
제공되어짐을 알 수 있다. 프로그래머는 4개의 인터페이스를 이용해서 필요한 모든일을 할 수 있는데 인터페이스를 통해서 실제
내부적으로 어떠한 일이 일어나는 지와 내부의 데이터가 숨어(추상화)되어 있음을 알 수 있다. 사용자는 각 인터페이스를 조절해서
필요한 일을 수행하게 된다.
여기에서 클래스의 이름은
Light라고 했다. 자 이제 여러분이 전구를 하나 샀다고 하면 이로서
It이라는 새로운 객체를 생성된 것이다. 여러개의 전구가 필요할 수 있는데, 그럴 때마다 서로 다른 이름을 가지는 객체를 생성시키면 된다.
It객체는 클래스
Light를 참조해서 생성된 객체이며
new라는 키워드를 통해서 생성된다(돈주고 전구하나 사는 것과 동일하다). 여기에서 우리는 클래스와 객체의 이름간에 연결이 있음을 알 수 있다.
위의 같이 클래스와 객체간 연관관계를 연결하는
다이어그램(diagram)형식의 구성도를 그릴 수 있을 것인데,
UML(Unified
Modeling Language)라는 도구를 이용해서 그릴 수 있다. 위의 경우는 클래스와 객체의 가장 단순한 예이지만
객체자체가 클래스가 될 수 있고, 상속등이 일어날 수 있으므로 실제로는 꽤나 복잡한 구성도가 만들어지게 된다. UML은 그
자체가 하나의 학습분야이므로 여기에서는 자세히 다루지 않을 것이다. 이런것이 있다는 정도만 이해하고 넘어가도록 하자.
2.7 객체는 서비스를 제공한다.
뻔한 얘기다.
은행업무-1객체는 고객에게 은행서비스를 제공하기 위해서,
It객체는 밝게 비춰주는 서비스를 제공하기 위해서 존재한다.
3 OOP (Object-Oriented Programming) 개론
이 글은 제가 오래전 잡지에서 본 강좌를 타이핑하여 파일로 저장해둔 것을 올린 것입니다.
아쉽게도 잡지명이나 저자 이름은 오래된지라 기억이 나지 않지만 전문을 올렸으니 잘 읽어보시기 바랍니다.
3.1 Object-Oriented Programming의 등장
3.1.1 소프트웨어 위기 (Software Crisis)
컴퓨터가 출현하고 그 기능이 발달함에 따라 우리들은 그것을 사용하여 보다 편리하고 윤택한 생활 - 정말 윤택하게 되었는지
아닌지에 대한 언급은 하지 않도록 하겠다 - 을 하게 되었다. 그에 따라 소프트웨어의 수요가 기하급수적으로 증가하게된다. 결국
공급이 수요를 따라가지 못하는 상태에 이르게 된다. 하드웨어의 발전은 눈부시도록 놀라운데 그에 비하면 소프트웨어의 발전은 그
발치에도 미치지 못하고 있는 것이다. 이러한 위기상황 속에서 이를 극복하고자 하는 노력을 구체적인 방법론으로 표현한 것이
소프트웨어 공학 (SE : Software Engineering)인데, Object-Oriented
Programming(Paradigm)도 바로 이 SE의 한 범주에 속한다고 할 수 있겠다. 집채만한 공룡이 메추리알 크기의 뇌를 가지고 있는 상태라고 볼 수 있을 것이다.
3.1.2 소프트웨어의 구성 방법의 변천
초창기에는 모든 소프트웨어를 단지 하나의 Procedure로 만들어 냈다. 그러나 많은 시간과 여러 사람의 노력이 필요한 큰
시스템을 구축하려고 할 때에 이런 방법은 적절하지 못하다. 그래서 큰 프로그램을 각 기능별로 여러개의 Subroutine으로
나누어(Functional Decomposition) 독립적인 부분으로
만들어(Modularization)
여러사람에게 할당하고, 각각의 모듈이 완성된 후에는 그것들을 서로 짜맞추어 하나의 시스템으로 완성하는 방법을 사용하게 된다.
이것을 Modular Programming이라고 한다. 이 Modular Programming과 함께 몇몇 규칙들을 적용하여
Structured Paradigm이라는 소프트웨어 구성방법이 생겨나게 되었으며, 지금까지도 널리 사용되고 있다.
3.1.3 Structured 방법의 문제점
기존의 Structured 방법은
처리(Process)를 중심으로 하고 있다. 바로 이점이 문제가 된다.
데이타(Data)
는 단지 강의실에서의 칠판처럼 필요할때마다 썼다 지웠다하는 보조 수단으로 여겨 그다지 중요시하지 않게 생각했다. 데이터를 독립된
단위로 보는 이러한 시각은 처리해야할 데이터의 절대적인 양자체가 적었을때는 크게 문제가 되지 않겠지만, 요즘처럼 다루어야 하는
데이터의 기본단위가
기가가 되는 경우에는 문제가 된다. 많은 데이타를 공유해야만하고, 원하는 데이타를 여기저기 마구 불러 사용하는 상황은
Modular Programming의 원리를 어기게 되었고 따라서 모듈의
재활용성(Reusablity)이 떨어지게 된 것이다.
DBMS(DataBase Management System)를 사용하여 이런 문제를 다소 해결할 수는 있으나 이로서는 충분하지 않다.
3.1.4 Object-Oriented Paradigm의 등장
프로그램의 재활용성을 높이기 위해서는 Modular Programming, 이를 위해서는 Procedure뿐만이 아니라 데이타도 모듈화 되어야 한다는 방법론이 등장했으며 이것이
Object-Oriented Paradigm의 중요한 기본 요소가 되었다. 1960년대에 등장한
Simula는 현실세계를 Simulation하는 것을 주목적으로 하는 프로그래밍 언어였는데, 이 프로그램에 도입된 프로그래밍 개념이 바로 Object-Oriented Paradigm의 효시가 되었다.
3.2 OOP의 기본개념
Object는 데이타와 이와 관련된 Procedure를 한데 묶어 표현한 소프트웨어 패키지이다. 이는현실세계가 처리중심이 아닌 사물(객체 : Object)중심으로 이루어졌다는데에 바탕을 둔 것이다.
세포(Cell)
를 예로 들어 생각해 보자. 세포는 핵, 미토콘드리아, 세포질, 세포막 등으로 이루어 졌는데, 이러한 세포의 구성 요소들에게는
각각의 역활이 주어져 있다. 그러나 기관의 입장에서 살펴면, 세포의 구성 요소들이 어떠한 일들을 하는지는 그다지 중요한 사실이
아니다. 단지 단백질이나 무기질을 세포내로 전달해 주면, 세포는 그것들을 가지고 자신의 임무만을 수행하면 되는 것이다. 세포내에
어떠한 구성원들이 있는지는 알 필요도 없고, 단지 세포 그 자체로서만 인식되면 충분한 것이다. Object도 이와 마찬가지로
생각하면 쉽게 이해가 갈 것이다.
3.2.2 Abstract Data Type & Data Abstraction
프로그래머가 기존의 Data Type을 이용 - 조합 - 하여 정의한 새로운 Data Type을 Abstract Data
Type이라고 하며, 이것을 Data Abstraction(데이터 추상화)이라한다. 이때 일반적으로 새로운 데이터와 그 데이터에
대한 연산까지 함께 묶어서 - 즉 객체단위로 - 정의한다. 이렇게 함으로써 사람의 생각을 한단계 높여, 구체적인
Low-Level(Primary) Data와 연산이 아닌, 추상화된 Data와 연산을 다룰 수 있게 된다. 이 Data Abstration은 복잡한
데이타(Complex Data)를 다룰때에 효과적이다. 실제로 "Program = Level of Abstraction"이라는 관점도 있다. 가장 간단한 형태의 데이터 추상은 구조체일 것이다.
3.2.3 Encapsulation
Data Abstraction를 이용하면
Encapsulation을 달성할 수 있다.
필요한 데이타와 Procedure를 모아 캡슐에 담는 것에 착안하여이렇게 이름을 붙인 것이다. 실제로 이
Encapsulation으로 인해 생겨난 결과가 Object이다. 예를 들면, Nucleus(핵),
Mitochondria(미토콘드리아), Membrane(세포막)등의 변수들과 그와 관계된 함수들을 Cell(세포)이란
object내에 정의해 놓은 것이다. 이렇게 함으로써 우리들은 자세한 부분까지 신경을 쓸 필요가 없고 단지 세포라는
Object와 Object로의 입출력 데이터만 생각하면 된다.
3.2.4 Infomation Hiding
Encapsulation으로 인해 내부의 데이타는 외부로 부터 고립되었다. 데이타는 필요한 때에 단지 외부로부터의
Message에 의해서만 접근되어질 수 있는데, 이러한 것을 Information Hiding(정보 은닉)이라 한다. 만약
Object내의일부분을 수정하였다고 해도 그 변화는 단지 Object내에서만 영향을 끼치고, 이로 인하여 완전히 모듈화가
이루어지는 것이다.
3.2.5 Composite Object
한 Object가 다른 Object를 포함할 수 있는데 이를 Composite Object라 한다. 이렇게 함으로써 포함된
Object를 새로운 Object의 한 부분으로 단순화시킬 수 있고, 그에 대한 자세한 내용을 알 필요도 없으며 많은 주의를
기울일 필요도 없이 사용할 수 있다. 미토콘드리아와 세포와의 관계를 생각하면 될 것이다.
Message는 Object사이의 소통을 가능하게 하는 방법이다. Message는 Receiver, Method,
Parameter의 세부분으로 구성되어 있는데, 예를 들어 "Car go: 20" (이것은 Smalltalk에서 사용되는
표현이다. C++에서는 Car.go(20)의 형태이며, Object-Oriented 방법을 지원하는 Programming
Language에서 Message의 구성요소들의 순서는 일반적으로 같은 경우가 많다.)라는 Message에서 Car는
Receiver이고 go:는 Method, 20은 Parameter이다. 쉽게 알수 있듯이 이 Receiver는 대상이
되는(Message를 수신하는) object의 이름이고,go:는 Car Object내에 정의된 Procedure(또는
Function)인데 Object-Oriented방법에서는
Method라고 부른다. 20은 Method의 Parameter이다. Parameter는 경우에 따라 필요하지 않을 수도 있다. Object는 Message를 통해서만 접근될 수 있다.
3.2.7 Overloading
같은 Method이름에 하나 이상의 의미를 부여하는 것을 Overloading이라 한다. 예를 들어 Circle,
Triangle, Rectangle 이라는 세 Object는 도형이라는 공통점을 가지고 있다. 이러한 도형을 그리기 위해
Method를 정의한다고 하자. 세 도형을 그리는 방법은 확연하게 다르다. 그러므로 각각 CircleDraw,
TriangleDraw, RectangleDraw라는 별개의 이름으로 된 Method를 만들어야 하는데, 이러한 불편함을 없애기
위해서 Draw라는 한개의 공통된 Method이름을 사용한 세개의 method를 만들어 각각의 object에 정의한다. 단지
어떤 Receiver에게 Message가 수신되는가에 따라 세가지의
Method(Draw)
중 하나가 결정되어 사용되는 것이다. 그러므로 "Circle Draw:10"이라는 Message가 주어지면 반지름이 10인 원을
그릴 것이고, "Rectangle Draw: 30 20"인 Message로는 가로 30, 세로 20인 직사각형을 그 것이다.
3.2.8 Overloading의 장점
예를 들어 Shape라는 Object가 있다고 가정해 보자. 이 Object는 위에서 예로 든 세가지의 Object중 하나의
값을 가질 수 있다고 하면, Program내에서 이 Shpae를 그린다고 할 때 기존의 방법으로 하려면 세가지의 선택문으로
표현되어야 한다.
if Shape = Circle then CircleDraw
else if Shape = Triangle then TriangleDraw
else RectangleDraw
이렇게 하게되면, Program내에서 Object에 대한 상세한 내용까지 Programmer가 알고 있어야 하므로
Programmer에게 부담이 된다. 나중에 Shape에 새로운 Object(예를 들면, Hexagon 같은)를 추가된면 역시
Program내에 수정이 가해진다. 그러나 Object-Oriented방법으로는 간단하게 "Shape Draw:라는 문장으로
충분하다. 새로운 object를 추가하더라도 Program을 수정할 필요 없으므로 확장성이 좋고, Program내에서
Object에 대한 자세한 내용을 알 필요가 없으므로 Information Hiding이 가능해 지며, 사용하기에도 편리하며,
이 모든 장점으로 인 Module화가 가능해진다.
3.2.9 Polymorphism
공통된 Interface를 사용하여 하나이상의 기능을 수행할 수 있는 것을 Polymorphism이라고 한다. 이것은
Overloading과 Overriding(특별한 형태의 Overlading)을 보다 일반적으로 일컫는 표현이다.
Class는 Method와 Attribute(속성)들을 포함하는 특정한 형태의 Object를 정의하는
틀(Template)
이다. 따라서 Class는 금형과 같이 수많은 복제품을 만들어 낼수 있으며, 이 복제품을 Instance라고 한다.
Instance는 단지 (Value)들 만을 포함하고 있으며, 따라서 이 Instance에 Method가 수신되면 Class에서
Method를 찾아 수행한다. 그러므로 'Object'는 Class의 Instance라 고 할 수 있다. 세포로 얘기하자면
어떠한 세포로도 분화 가능한
만능세포가 Class 쯤에 해당한다고 볼 수 있다. 만능세포는 자신이 위치하는 기관에 따라서 신경세포, 근육세포, 뉴런세포등 다양한 세포를 만들어 낸다.
3.2.11 SuperClass와 SubClass
한 Class가 다른 Class의 특정한 형태의 하나로 정의될 때 기존의 Class를 SuperClass, 새로운 Class를 SubClass라 한다.
3.2.12 Inheritence(상속)
SubClass는 SuperClass의 모든 것들을 상속 받을 수 있다. 즉, SuperClass의 모든 Method와 Attribute들을 별도의 정의없이 사용할 수 있다.
3.2.13 Class Hierarchy
Class Hierarchy란 Class들의 Tree모양의 구조를 말한다. 이것은 -이론적으로- 제한없이
중첩(Nesting)
될 수 있으며, Inheritance는 축적되어 아래 단계로 내려간다. 즉, 한 Class에서는 그 상위 Level에 있는 조상
Class의 모든 성질을 계승받을 수 있다. 이 Class Hierarchy는 정보와 정보를 다루기 위한 방법들을 전승할 수
있다는 장점을 가진다.
3.2.14 예외(exception)의 처리 : Overriding
앞의 예에서 Vehicle Class에
비행기를(Aircraft)
라는 SubClass를 첨가시킨다고 하자. Vehicle을 움직이게 하는 Method가 'go'라고 할때, go 신호를 보내면
일반적으로 시동을 걸고 Hand Break를 푼 후에 엑셀레이터를 밟아 앞으로 나아간다. 하지만 비행기는 자동차와 상당히
다르다. 스위치를 눌러 시동을 건 후, 여기저기 게기판을 만진 후에 하늘로 날아오른다. 그후에도 고도조절, 속도조절, 기류도
한번 살펴보고 건물이나 산과 부딕치지 않도록 조심하고...
실제 Class의 경우에 대해서 생각해보자. Method의 이름을 다른 것으로 바꿀 것인가? 그러면 일관성이 없어진다. 그렇다고
SuperClass인 Vehicls에서 'go'란 Method를 한단계 밑으로 끌어내려 정의한다면, 똑같은 내용을 Auto,
Truck, Bus의 세 Class에 정의해야 하므로 중복이 되어 비효울적이다. 이때는
SuperClass(Vehicls)에 있는 Method는 그대로 두고
SubClass(Aircraft)
에 'go'라는 Method를 재정의하는 것이다. 그러면 Message를 수신하는 Object가 어떤지에 따라서 적합한
Method가 선택되어 실행된다. 이렇게 SuperClass에 있는 Method의 이름으로 새롭게 Method를 재정의 하는것을
Overrding이라 한다.
3.2.15 Virtual Class(Abstract Class)
단지 구조적인 목적으로만 사용되기 위하여 설계된 Class를 말한다. 앞으로 사용될
기능들(Attribute,
Method)을 모아놓기만 하고 구체적인 구현은 나중으로 미루어, 다른 Class들의 Base Class로만 사용된다. 따라서
Virtual Class의 Instance는 존재할 수가 없다. Abstract Class라고도 하지만, Abstract
Data Type과의 혼동을 방지하기 하여 일반적으로 Virtual Class라고 한다.
3.2.16 Multiple Inheritance(다중 상속)
한 Class가 여러개의 SuperClass를 가질 수 있도록 하는 것을 말한다. '철강회사의 노동조합장'의 경우를 예로
들어보자, 그는 유능한 용접공이며 또한 회사의 업무를 관장하는 간부이기 하다. 단지 Single Inheritanc만이
가능하다고 하면
그림에서처럼 간부의 역활을 이중으로 정의해야 하므로 비효율적이다. 이때 Multiple Inheritance를 이용하면
효율적이다. 하지만 이때에 주의해야 할 사항이 있다. 같은 이름으로 정의된 Method가 각각의 SuperClass(용접공,
조합장)에 존재하면, 이때에는 어떤 SuperClass의 Method를 사용해야 할지 결정할 수가 없다. 즉, Conflict가
일어나게 되는 것이다.
Multiple Inheritance를 이용하면 이러한 문제를 해결할 수 있다. 그러나 함부러 마구 갖다붙이지 않도록 주의를
기울여야 한다. 중요하지 않은 곳에 오용되는 경우가 종종 있다. 위의 예에서 '조합장'의 경우를 생각해 보자. Multiple
Inheritance를 올바르게 사용한 것인가? 이전에는 용접공이었지만 조합장이 된 후에는 실제로 용접을 하지않고 회사의
업무만을 관리하게 되었다면 그때부터는 사실상 용접공이라고 할 수가 없다. 이러한 경우에는 용접공의 계승을 없애버려야 한다.
계승되는 SuperClass의 성질을 온전히 포함하고 있는지 살펴보는 것이 올바르게 Multiple Inheritance를
사용하고 있는지 여부의 판단 기준이 된다.
3.2.17 Class Hierarchy의 구성
제대로 된 Class Hierarchy를 구성하기 위해서는, 우선 나중에 쉽게 재활용될수 있도록 일반적인 목적으로 설계되어야
한다. 또한 이 Class Hierarchy는 현실세계를 잘 반영할 수 있어야 하며, Method는 가능한한 가장 높은 최상의
단계에서 정의되어야 중복을 줄일 수 있다.
3.3 Object-Oriented 방법을 이용한 Software의 구축
3.3.1 Reusability(재활용성)
Object-Oriented 방법의 가장 중요한 착안 사항이 바로 이 재활용성일 것이다. Reusable Module이 많이
마련되어 있다면 그것들을 이용하여 Software를 구축하면 보다 적은 노력만이 필요할 것이다. 실제로 Reusable
Module을 설계하는 데에는 설계, 분석의 과정을 거쳐야 하므로 설계상의 자세한 내용은 줄이고 개념적인 것만 살펴보자.
Reusable Module을 설계하는 것은 대게의 경우 필요한 것을 그때 그때 만들어 쓰는 것보다 더 많은 계획과 노력을 필요로 한다.
OOP의 핵심은
추상화에 있는데, 이 추상이라는 것은 다루고자하는
객체들의 공통된 속성을 뽑아내어서 일반화된 계층을 만들어 내는 행위다. 그러므로 다루어야 할 객체들과 주변환경에 대한 폭넓은
이해가 우선적으로 필요하다. 삽살개, 진돗개, 치아와 등에 대한 공통적인 특징들을 제대로 알고 있어야 비로서
개를 제대로 정의할 수 있는 것과 마찬가지다. 많은 시간이 필요할 수 밖에 없다.
이들 Reusable Module은 Class 를 중심으로 설계된다. 전에 언급한 Class의 장점들 - 현실세계를 잘 반영할 수 있으므로 인간의 생각을 표현하는데에 수월하고,
상속(Inheritance)
을 이용하여 확장이 쉬워지며, Polymophism을 적용하여 특별한 예외 경우를 잘 처리할 수 있는 점 등 - 이
Module을 설계하는데 꼭 맞게 적용되기 때문이다. Reusable Class는 필요한 것들을 직접 설계해서 얻을 수 있을
뿐만 아니라, Programming Language에서 제공되기도 하고, 때로는 상점에서 구입하는 것이 효율적일 때도 있다.
3.3.2 Object를 직접 사용한 Software의 구축
기존에 만들어진 Reusable Object를 모아 Software를 구축할 수 있다 하지만 이 방법은 필요로 하는
Object들을 모아 실제로 구동시키는 새로운 Object를 만들어야 하는데 불편함이 있다 (Program = Class
Libraries + Solution Classes). 물론 기존의 방법에 비하면 이 정도로도 훌륭하지만, 더 나은 방법이 있다.
3.3.3 Simulation
그 방법은 Class Library들을 모아 Modeling을 하는 것이다. 즉, 기존의 Class들을 이용하는
High-Level Object 까지도 미래의 필요에 대비하여 설계하는 것이다. 은행의 전산처리 System을 구축하는 것을
예로 들어보자. 여기에는 입출금 계산, 신용카드 결재, 각종 공과금 자동납부 등 여러가지 작업들이 필요할 것이다. 이때에
Class Library들을 이용하여 입출금 계산 System, 신용카드 결재 System, 공과금 자동납부 System 등을
미리 설계해 놓으면, 나중에는 단지 이것들을 끼워 맞추기만 하면 되므로 Class Library들을 직접 이용하여 모든 것을
다시 설계하는 것보다 훨씬 수월할 것이다. 신용카드 결재 방법을 바꾸었다고 하자. 그러면 단지 신용카드 결재 System, 그
중에서도 특정한 Class들만을 고치면되므로 수정도 용이하게 할 수 있다.
3.3.4 Rapid Prototyping
Prototype이란 한마디로
'시험판(Trial
Version)'이라고 할 수 있다. 실제로 기업에서의 간부들은 '그들이 정말로 원하는 것이 무엇인지'를 제대로 알지 못하고
있는 경우가 대부분이다. 그들에게는 프로그램이 동작하는지 아닌지만 중요할 뿐이다. 자신이 만들 프로그램이 어떻게 돌아갈지를 미리
확인하는 차원에서 필요하기도 하지만 윗분들의 정서적안정을 위해서 만들필요가 생기기도 한다.
3.3.5 System의 구축
Reusable Class들의 Library를 구축한다. 이 Class들을 이용하여 Working Model을 구축한다.
Rapid Prototyping을 이용하여 System을 구축한다. - 필요에 따라서는 이전의 단계로 되돌아갈 수
있다(Feedback).
3.4 Object-Oriented 방법의 장점과 단점
그림출처:crisp
OOP면 모든게 해결될 거라고 생각하는 개발자들이 있다. 최신이 언제나 좋은 건 아니다. 자기가 잘 할 수 있는 방식으로 하는게 최고다. 자고로 프로그램이란건 돌아가야 하는하고 기본적으로 자신을 위해서 만드는 것이기 때문이다.
우선 짚고 넘어가야 할 점은, 기존의 사고 방식을 가지고 단순히 Object-Oriented Language를 사용하여
Programming을 하는 것은 별로 도움이 되지 않는다는 것이다. 이제까지 가지고 있던, Programming 할 때의
기존의 사고방식을 과감히 탈피하여 새로운 개념을 가지고 이에 적합한 분석과 설계가 뒤따라야만 Object-Oriented 방법의
장점을 충분히 살릴 수 있을 것이다.
- 설계 시간의 단축
기존에 만들어진 Module을 이용하여 Rapid Prototyping의 방법으로 소프트웨어를 구축하므로 시간을 절약할 수 있다.
- 질적인 향상
이미 충분히 검토되고 시험된 모듈을 이용하여 모아서 프로그램을 만들기 때문에, 필요에 따라서 그때그때 만든 것들 보다 더 높은
질을 가진 프로그램을 만들 수 있다. 이점은 Object-Oriented 방법으로 만들어진 Reusable Module을
사용하기 때문에 이루어지는 것이지 Object-Oriented 방법 자체가 질적 향상을 가능하게하는 것은 아니다.
- 유지 보수의 수월함
Object-Oriented 방법은 현실 세계를 그대로 소프트웨어 시스템으로 반영할 수 있으므로 결점을 발견하기가 쉽다. 또한
모듈화 되었으므로 결점을 고쳐도 그 파급효과가 다른 모듈에 끼치는 영향이 거의 없으므로 시스템을 유지하기가 수월하다.
- 제작 비용의 감소
기존에 만들어진 프로그램을 이용할 수 있으므로 프로그래밍의 노력이 줄어들고, Rapid Prototyping을 통해 시스템
디자인의 노력을 줄일 수 있고, 필요로 하는 모든 Class Library를 일일이 제작할 필요가 없이 시중에 나와있는 것들을
구입하므로, 회사의 경영 차원에서도 제작 비용을 줄일 수 있다.
- 대형 시스템구축의 수월함
Modular Programming과 Polymorphism도 대형 시스템의 구축을 가능하게 한다. Object-Oriented
방법으로만 가능한 그러한 것은 아니다. 일반적으로 대형시스템이라고 하는 것은 많은 추상화 단계를 거치기 마련이다. 그러므로
추상화를 지원하는 OOP가 좀 더 수월하게 대형시스템을 구축하도록 도와주리라는 걸 예상할 수 있으며, 실제로 그렇다.
- 더 나은 information 구조
현대의 기업사회에서 요구하는 복잡한 정보를 효과적으로 표현할 수가 있다. 이것은 Data Abstraction으로 가능하다.
- 적응성(adaptability)의 향상
수정을 가해도 그 영향이 국소화 되므로 필요한 부분만을 고쳐 쉽게 새로운 스템에 적용시킬 수 있다.
- Object-Oriented 방법의 미 성숙
어느 정도 기본적인 것은 갖추어 졌지만 Object-Oriented 방법은 아직 제대로 성숙되지 못했다. 이 방법을 믿고 사용하는데에 어려움이 따른다.
- 표준의 필요성
Programming Language에 대한 표준이 제대로 되어 있지 않기 때문에 프로그램을 이식하는데에 문제점이 있다. 이렇게
되면 소프트웨어를 같은 회사에서 구입해야 하고 다른 회사의 것은 섞어서 사용할 수 없게 된다. 이것은 큰 문제점을 야기할 수
있다. 만약 거래 회사가 망했다고 하자. 어떻게 할 것인가?
- 더 나은 도구(tool)의 필요성
Object-Oriented 방법을 바탕으로 시스템을 구축하는데 필요한 Tool 들은 몇가지가 있다. Object를 쉽게 설계할
수 있도록 해주는 것, Reusable Object들의 Library를 유지할 수 있도록 해주는 것, Data Input
Form과 출력을 셜계하고 유지할 수 있도록 해주는 것들이 있다. 새로운 방법론에 비해 그것을 지원해 줄 수 있는 Tool 들은
늦게서야 만들어지기 마련이지만, Object-Oriented 방법은 기존의 것과 상이하게 다르기 때문에 그들을 이용하기
힘들다는데 문제가 있다. 예를 들면, 현재 Class Library Management Tool 들은 기껏해야 간단한
Browser 정도만 제공할 뿐이다. 그들의 체계적인 분류, 사용 목적, 사용 방법 등에 관한 것은 충분히 지원하지 못하고 있다.
- 느린 개발 속도
객체지향은 처리하고자 하는 일에 대한 명확한 이해를 필요로 한다. 전체에 대한 잘못된 이해 혹은 분석이 부족한 상태에서 일을 시작하게 되면 프로그램 구조자체에 문제가 생길 수 있다. 초기설계에 많은 시간이 소모된다.
- 느린 실행 속도
Object-Oriented Language로 만든 소프트웨어들은 대체적으로 실행속도가 느리다. 추상화에는 많은 컴퓨팅파워가
소모된다. 기능이 강력하고 많은 만큼 속도가 상대적으로 느린 것은 당연하다 할 것이다. 하지만 Object-Oriented 방법
자체가 실행 속도를 중심으로 설계된 것은 아니기 때문에 속도는 큰 문제가 아닐 수도 있다.
- Conversion에 사용되는 비용
기존의 방법론을 Object-Oriented 방법으로 바꾸는 간단한 문제가 아니다. 새로운 Programming Language,
DBMS
뿐만 아니라 그에 해당하는 여러가지 Tool 들, Graphics가 지원되는 Hardware System 들이 OOP를 필요로
한다. 그러므로 기존의 패러다임을 OOP로 바꾸는 작업이 필요하게 되는데, Conversion에 소요되는 비용을 간과할 수는
없다. 또한 물리적인 비용 뿐만이 아니라, Programmer와 설계자, Manager에게 들어가는 교육비용또한 상당하다.
3.4.3 장단점의 적절한 조화
- 성숙성
Smalltalk이나 C++, 그외의 기존 Programming Language에도 Object-Oriented 방법이 추가되어
새롭게 등장하는 프로그래밍 언어들은 OOPL을 사용하는 데에는 큰 불편함이 없다. 또한 이 새로운 개념을 전문적으로 취급하는
연구단체나 기업이 점점 늘어나고 있으며 이러한 연구단체나 기업들의노력으로 단점을 충분히 파악할 수 있게 되었다.
기존의 방법론과 비교해 보고 싶으면 동일한 Application을 기존의 방법을 이용하는 또다른 Team에게 맡겨보면 된다.
아마도 세가지 정도의 Application을 완성할 때 쯤 되면 Object-Oriented 방법의 장단점을 명확하게 파악할 수
있을 것이다. 이때 주의할 점은, Team 구성원 누구에게도 자신들이 시험의 대상이 되고 있다는 것을 알게해서는 안된다는
것이다. Heroic Effect(자신들이 시험의 대상이 되고 있다는 사실이 평소보다 더 열심히 한다든가 하는 등의 영향요소로
작용제로 Application을 개발할 때보다 수정하는 경우에 비용이 더 많이 소요되는 경우)가 종종 있기 때문이다.
객체지향은 패러다임의 변화를 요구하게 된다. 이 패러다임의 이해도에 따라서 개발자간에 커뮤니케이션 하는데 어려움이 생길 수
있다. 이차이는 개발자의 코딩능력과는 별개다. 십수년의 경력을 가지고 있다고 하더라도 객체지향적으로 프로그램을 만들어오지
않았다면 커뮤니케이션에 어려움이 생길 수 있다. 이러한 개발자간 커뮤니케이션의 문제점은 패턴에 대한 학습을 선행함으로써 상당부분 해결 가능하다.
4 관련글
C프로그래머를 위한 C++
저도 덕분에 다시한번 읽었는데요,,, 처음 프로그래밍을 시작하시는분께는 좀 버겁지 않나 생각되는 글이긴 합니다만 한번 알아둘 필요는 있습니다.
그래서 짧게 간추리자면 OOP 의 특징을 가지는 언어는 다음의 특징을 주로 가집니다.
1. Abstraction(Indirection)
2. Encapsulation
3. Polymorphism
저도 살짝 가물가물하긴 한데, 아마 맞을겁니다 :) 다른건 지금 특별이 이야기하지 않겠구요, 지금 이야기하고자하는건 Abstraction(Indirection)에 대한 이야기입니다.
Abstraction, 예전에 제가 존경하는 교수님중 한분이신 강순주교수님의 OS 수업을 들을때 가장 기억에 남는 용어중 하나입니다. 한글로하자만 "추상화" 이지요.
개인적으로 정말 재미있게 들은 수업중에 하나인데요, 교수님께서 OS에서 가장 중요한것은 바로 추상화! 라고 하시며 Active 하게 수업하셨거든요, 물론 과제도 매우 Active해서 학생과 조교 모두 밤좀 샜었습니다. Anyway, 추상화는 현대 프로그래밍에 있어서 정말 중요한것중에 하나입니다.
지난번에 printf 와 NSLog를 설명하면서 이런이야기를 한적이 있습니다. 우리는 단지 저녀석들만 써주면 된다고, 그 아래서 이게 어떻게 컴퓨터가 알아듣고 원하는 위치에 어떠한 방식으로 hello world를 찍어내는지는 우리가 전혀 알필요 없다고 말입니다. 그냥 컴파일러가 알아서 해서 OS에서 정확하게 일처리를 해준다고 이야기 했습니다. 바로 이것이 추상화(Abstraction) 입니다.
간단히 예를 들어 설명해보겠습니다. 얼마전에 제가 사기를 당해 사기친 인간의 계좌를 정지시켜버렸는데요, 은행에서 제가 한 일은 은행에 가서 서류에 사인을 한것이지요. 자 그럼 그 은행원은 무엇을 했을까요? 그 서류를 가지고 해당은행에 연락을 하구요, 그 해당은행은 사기관련 담당자에게 연결을 해주었을겁니다. 담당자는 전산부서에 사시꾼의 계좌정지요청을 했을것이구요, 전산담당자는 경찰쪽에 사기여부를 확인후 (이때도 전화를 걸거나 해당 사이트에 조회를 했겠지요) 해당계좌에 대해 영구정지를 시켰겠지요.
전 저 과정을 알필요가 없습니다. 사실 제 추측이기도 하구요, 그냥 제가 한일은 서류에 사인하고 기다리고있었습니다. 나머지에 대해선 알필요도 없고 그 결과, 사기꾼의 계좌가 정지되었다는것만 알만 되는것이지요. 바로 이게 추상화란겁니다. 내가 명령을 내리면 그 아래서는 여러가지 뭘 하더라도 어쨋든 원하는 결과가 나오는것이지요. 이것을 약간 다른 느낌으로는 Indirection (간접접근)이라고도 합니다.
이제부터는 추상화보다는 인다이렉션에 초점을 맞추어 이야기하고자 합니다.
한가지 예를 더 들어보지요. (그냥 제 예시일뿐입니다, 실제와는 다를 수 있습니다)우리의 아이폰이 슬프게도 고장이 났다고 칩시다. 그러면 우리는 애플에 전화를 걸겠지요. 그러면 애플에서는 KT로 전화하라고 할껍니다. KT로 전화하면 예쁜목소리의 상담원을 수차례만에 만나서 KT 아이폰 부서로 연결을 해주겠지요. 그럼 담당부서에서는 해당 AS 기사에게로 연결해줄것이고 기사는 아이폰 수리 절차를 알려줄겁니다. 그럼 우리는 그 절차대로 해서 수리를 받게되겠지요.
오마이갓. 엄청 짜증나는 상황입니다. 이것이 바로 인다이렉션입니다. 직접적인게 아니라 간접적으로 일처리를 한다는거죠. 이 예에서 인다이렉션의 장단점이 모두 나타납니다.
장점은, 단순하다는겁니다. (걷보기에요) 애플은 단순히 KT에 일을 떠넘기면 됩니다! KT내부에서도 중심부에서 담당 부서로 일을 떠넘기면 단순해지는 문제이지요! KT에서도 만약 아이폰 4G가 새로 나온다면 아이폰 4G 담당부서를 새로 만들어주기만 하면 KT에 전화해서 그쪽으로 넘기면 되지요! 유지보수도 편리하고 좋다는겁니다. 만약 이게 이렇게 안되있다면 KT는 소비자에게 전 담당원 전화라인을 모두 알려주어야겠지요, 아마 수천개의 전화번호리스트를 소비자에게 주어야겠지요. KT입장에서는 끔찍하지요. (소비자는,, 좋을지도 모르겠습니다만. ㅎㅎ)
단점은, 소비자 입장에서 한번 생각해봅시다. AS 기사와 통화하기위해 도대체 몇번을 통화한거죠? 애플, KT상담원, 담당부서직원, 담당기사, 4번나왔습니다. 자 이때쯤되면 한번쯤 버럭할겁니다. (것도 정말 연결하기 힘들겠지요? 사실 KT는 경험안해봐서 모르는데 SKT는 그랬더랍니다..............) 짜증나지요. 시간도 엄청걸렸구요. 이것은 프로그래밍에서도 그대로 적용됩니다. 바로 퍼포먼스가 떨어집니다. 저렇게 여러번을 거치니 당연히 같은 기능을 하더라도 느려질수밖에 없습니다. 사실 이것이 바로 임베디드 시스템을 위한 프로그래밍에서 C를 사용하고, OS를 만들때 (심지어 Mac OS X도 C로 작성되었습니다) C를 사용하는 이유이기도 합니다. 그나마 다행인건 컴퓨터는 짜증은 내지 않습니다. 이짓을 수천번 수만번 시켜도 다행이 그렇게 고장을 자주일으키지는 않지요. 물론 메모리관리를 잘못하면 배째라 죽어버리겠지만,, 괜찮습니다. 우리는 일단 편한게 먼저니까요 :)
감사히도 iPhone OS를 위해서는 우리는 조금 더 편한 OOP 기반으로 설계된 Objective C를 사용해야만 합니다. 이로서 우리는 프로그래밍 라인수를 상당량 줄일 수 있고 (실제 컴파일될때는 말이 다르지만요... 컴퓨터는 길게 받아들일겁니다.) 편하게 유지보수 및 신기능추가(업데이트)를 시킬 수 있다는겁니다.
자 이정도 이해했으면 OOP는 괜찮을 것 같습니다. 그럼 이 OOP를 이용한 프로그래밍을 시작해보겠습니다. 개괄소개가 너무 길어져서, 잠시 자르고 다음페이지에서 인다이렉션을 활용한 예제를 풀어보겠습니다.