Class 와 Obejct(instance). 그리고 Factory

객체지향에서 Class 의 존재는 매우 중요하다. inheritance(상속성), encapsulate(캡슐화), polymorphism(다형성) 의 세가지로 대표되는 객체지향의 특성은 대부분의 객체지향 언어에서 제공하는 Class 에 포함되어 있다. 사실 살펴보고 싶은것은 너무나 잘 알려진 앞의 3가지 특성이 아니라 Class 와 instance 의 관계에 대한 것이다.

당신은 Class 를 무엇이라고 생각하는가? 우리는 Class 를 무엇이라고 정의할 수 있을까? Prototype?(물론 패턴이름을 말하는것은 아니다). 또는 어떠한것의 원형(Orign) 이라고 생각할 수도 있을지 모른다. 또는 과자등을 찍어내기 위한 형틀에 가까운 무언가일지도 모른다.

약간 다른 얘기가 되겠지만 조금 옆길로 새보도록 하자. 컵을 공산품으로 만들기 위한 과정을 고민해보자. 일단 컵의 원형부터 먼저 만들어야 할 것이다. 그리고 시행착오를 거쳐 대량생산이 가능한 형태로 다듬어야 공산품으로서는 쓸만할 것이다. 이렇게 하나의 컵이 만들어지게 되면 생산을 위한 준비과정으로 들어가야 한다. 만들어진 시험작을 이용해서 형틀을 만들것이다. 그리고 만들어진 형틀을 이용해서 생산설비를 만들것이다. 만들어진 설비를 이용해서 생산을 시작하면 된다. 물론 필요한 수량만큼 생산을 해야 낭비가 없을것이다.

다시 본론으로 돌아와서 Computer Software 의 범용적 특징을 되새겨보도록 하자(물론 특별한 조건등은 그다지 고민하지 않기로 한다). File(또는 software)는 일반적인 경우 원래의 위치에서 다른위치(같은 물리적 disk내의 다른위치일수도 있다)로 복사(copy) 작업을 진행하는 경우 원본의 내부 또는 외부가 전혀 손상되지 않는다. 원본과 그대로 같은 내용의(inode 또는 생성일등은 틀려질 수 있겠지만) 복제품이 만들어 지는 것이다. 이렇게 만들어진 복제품은 완전히 원본과 동일한 동작을 하게된다. 이런 복사작업은 저장 미디어 뿐만이 아니라 로딩된 물리메모리에서도 동일한 개념으로 동작하게 된다.

Class 는 어떠한 객체를 생성하는 형틀의 역할을 한다. 그 자체로도 필요한 기능을 가지고 사용될 수도 있지만 Class 와 꼭 닮은 객체를 만드는데로 사용될 수 있다. 자루까지 쇠로 만들어진 튼튼한 망치정도면 적당한 비유가 될까? 망치로서의 용도도 충분히 가지고 있지만 그 자체로 다른 망치를 만들어내는 원형(prototype)의 역할도 할 수 있다. 물론 Computer 의 세계는 실제 세계보다는 좀 더 논리적인 개념하에서 동작하지만…

이렇게 원형이 되는 경우를 Class 라고 하며 이를 이용해서 생성된 결과물의 존재를 객체(Obejct) 또는 인스턴스(instance) 라고 한다. 이렇게 instance 를 찍어내는 Class 는 그 스스로 무언가를 생성하는것과 비슷한 동작을 하게 된다. 이런 일련의 과정을 짚어보면 Class 를 공장(Factory)라고 볼 수도 있을 것이다. 그럼 이런 과정들을 위해 만들어진 Class 들을 뜯어서 다시 손보고 개량하는 작업은 어떻게 불러야 할까? 그렇다. 답은 명료하다. 바로 “refactoring” 이다. 필자는 이러한 내용들이 refactoring 을 설명하는 대에 대한 가장 정확한 답이라고 확신한다.

instance 를 취급하는 방법은 각 환경에 따라 다르다. compiler 는 class 를 통해서 instance 를 생성할때 real memory(protected) 에 생성되는 포인터(pointer) 로서 이것을 취급한다. 물론 compiler 는 interperter 가 아니기 때문에, 이러한 동작들은 binary 가 실행되는 시점(runtime) 에 진행되게 된다.

Virtual Machine 의 대표격인 smalltalk 에서는 instance 의 생성작업은 좀 더 복잡한 동작을 가지게 된다. 근래에 가장 유명한 Smalltalk 구현체인 Pharo(CogVM) 을 예로 들어보자. CogVM 을 실행하면 주어진 인자(argument)에 따라 Smalltalk image 를 로딩한다. 이때 Smalltalk image 안의 모든 class 를 로딩해서 unique instance 로 메모리에 생성한다(물론 image 의 동작에는 이런 부분이 snapshot 형태로 포함되어 있기도 하지만.. 이런 부분은 논외로 한다). smalltalk 의 Class Browser(nautilus)에서 보이는 모든 class 는 사실 unique instance 를 이미 가지고 있다고 보는것이 맞다. class side 의 메서드(Method)를 사용하는 경우라면, 내부에서는 Class 에 대응되는 unique instance 를 통해서 해당 메서드를 실행하게 된다. 물론 Class 를 이용해서 instance 를 생성하게 되면 unique instance 와는 전혀다른 새로운 instance 를 생성하게 되는데, 이때 바탕이 되는 class 의 생성자(creator)를 이용하기 위해서는 Class 에 대응되는 unique instance 의 생성자 메서드를 이용하게 된다. 대부분의 Smalltalk Systam 은 재념적으로 비슷한 동작을 하도록 구성되어 있다.

이번 내용은 조금 긴 내용이 되었지만, 요점은 다음과 같다.

* Class == Factory
* sintance == Class 의 전사체
* class 로 만들어진 library 를 정리하는 작업 == refactoring
* Virtual Machine 환경과 Compiler 언어의 instance 취급방법에는 차이가 있다.

이렇듯 class 와 instance 의 개념을 좀 더 숙지하고 나면 이후 객체지향을 이해하는데 좀 더 도움이 될 것이다.

How to Using Design Pattern?

Design Patter 은 프로그래밍 코드의 모음이 아니다. 굳이 풀어보자면 UML 중 Class Diagram 에 가장 가까운 형태라고 보는게 표현식을 설명하는 좋은 방법일 것이다. 그렇다고 Design Pattern 이 Class Diagram 과 완전히 같다는 의미는 아니다. Design Pattern 은 프로그래밍 언어구조와 Sudo code(의사코드)의 관계와 비슷할것이다. 왜냐하면 Design Pattern 은 특정언어에 종속되지 않는 범용성을 가지는것이 기본이기 때문이다(물론 실제 코드를 구현하는 언어에 따라 다소의 차이는 있겠지만)

GoF 에 따르면 Pattern 은 Creation(생성), Structual(구조), Behavioral(행동) 의 세가지중 하나의 분류를 가진다고 얘기하고 있다. 그리고 이 목적별 특성은 Pattern 은 분류하는데 매우 유용하게 사용된다.

Design Pattern 에서 설명되는 Diagram 들은 UML 이 표준이 되기 전의 OMT 표기법을 기준하고 있기 때문에 UML 과 다소의 차이는 있곘지만 논리적으로 이해가 가지 않을 만큼의 차이점이 있지는 않으니 크게 문제는 없을것이라 예상한다.

Disign Pattern 은 보다 세련된 문제풀이를 위해 존재한다. 반드시 당신의 프로그램이 이러한 패턴을 사용해야 하는것은 아니지만, Design Pattern 을 이용하면 당신의 프로그램을 적은 노력으로 보다 세련되게 바꿀 수 있을것이다(물론 배우기 위한 노력이 들어가는것은 어쩔 수 없지만)

대부분의 Design Pattern 의 설명에는 동기(Motivation)가 같이 명기되어 있다. 이런 내용들을 먼저 한번 읽어보고 당신이 만들게될 프로그램에 적용할 수 있는 방법이 있는지를 생각해 보는것도 좋을것이다. 또는 패턴의 이름을 기억해두고 사전에서 꺼내쓰듯 사용하는 것도 좋은 방법이 될것이다. 하지만 제일 좋은 방법은 따로 있다. “백문이 불여일타”. 시험삼아서 당신이 할 수 있는 방법으로 시나리오를 만들고, 코드로 직접 구현해본다음, 이렇게 만들어진 것들을 Library 로 만들어서 필요할때 쓸 수 있도록 체화하는게 가장 좋은 방법이 아닐까?

What is Design Pattern?

Design Pattern 은 원래 Computer Science 에서 등장한 말이 아니다. 사실 Design Pattern 은 건축학자인 Christopher Alexander 의 다년간의 실험에 의한 결과로 등장한 이론이다. Alexander 는 그의 도시-건축-시공 에 대한, 도시의 발전과 개발계획에 대한 컨설팅 및 실험의 결과에서 도시의 발전은 그 형태의 필요에 따라 분류할 수 있는 형태가 존재한다는 것을 알았으며 이것을 표현하는 방법을 Pattern Language 라고 부르기 시작했다.

Erich Gamma 를 포함한 4명의 연구자들은 이 부분에 흥미를 느끼기 시작헀다. 사실 Alexander 의 실험은 결국 실패로 끝나고 학문적 성과로만 남는 결과가 되었지만, Design Pattern 은 전혀 생각지도 못한 분야에서 주목받게 되었다. 바로 Computer Science 라는 분야가 그것이다.

Xerox 의 Palo Alto 연구소에서 시작된 Object-Orientation Programming(객체지향 프로그래밍)과 Smalltalk 의 세계는 Personal Computer 의 물리적 성능의 한계때문에 이미 만들어졌음에도 불구하고 한동안 빛을 보지 못했다. Smalltalk 는 Star/Alto 머신 외의 일반 PC 에서 사용되기에는 너무 무거웠으며 C++ 는 C 언어에 비해서 Compile 속도가 너무 느렸다. 그러나 무어의 법칙대로 PC 의 성능은 비약적으로 발전했으며 소프트웨어 개발의 패러다임또한 변하기 시작헀다.

개발의 목표에 대해 기존에는 결과물의 성능이 최우선이었지만, 보다 개발의 편리성과 효율성이 중요해지기 시작했다. 기존의 Library 로 대표되던 Framework 은 재사용성과 프로그램 작업의 표율성을 위한 방향으로 만들어지기 시작했다. 기존의 Procedural(절차적) 프로그래밍 언어로는 한계가 오게 된것이다. 성능을 위해서만 발전한 언어의 Specification(명세) 만으로는 이러한 요구를 감당하기에는 역부족이었다. 이제 객체지향 프로그래밍 언어의 시대가 필요해지기 시작헀다.

객체지행 프로그래밍이 본격적으로 요구되게된 배경에는 프로그래밍 작업에 대하니 효율이 가장 컸다. Design Pattern(GoF) 이 사람들에게 다시 관심받게 된것은 어찌보면 당연한 순서일수도 있다. Design Pattern 의 목적 자체가 발견된 Pattern 을 통한 소프트웨어 개발에 도움이 되는 재사용성/업무의효율 에 있기 때문에 객체지향을 도입하는 목표와 Design Pattern 의 도입은 정확하게 일치한다고 봐아한다.