[본글은 http://bcho.tistory.com/884 에서 퍼온 글입니다.]



Node.js 설치하고 개발환경 설정하기

다운로드 하기

http://www.nodejs.org 페이지에서 install 버튼을 누르면 OS에 맞는 인스톨러를 다운로드 해준다.



다음으로 installer를 실행한다.



설치가 되었으면, 설치된 디렉토리를 PATH에 추가한다.

set PATH=%PATH%;c:\dev\was\nodejs

자아 이제 node.js가 설치되었는지 확인하자. node.js는 대화형 cli를 제공한다.



설치를 끝냈으면 이제 간단한 웹서버를 만들어보자

var http = require('http');

http.createServer(function(request, response) {

response.writeHead(200);

response.write("Hello, this is dog.");

response.end();

}).listen(3000);

console.log('Listening on port 3000...');

이 코드를 app.js로 저장한다.

다음으로 다음과 같이 해당 파일을 실행한다.



이제 웹브라우져로 확인해보면 다음과 같이 메세지가 출력되는 것을 확인할 수 있다.



다음으로 개발환경을 설정해보자, 개발툴은 eclipse 등 여러가지 툴이 있지만 개인적으로 IntelliJ를 만든 JetBrain社의 WebStorm (http://www.jetbrains.com/webstorm/을 추천한다. 유료이긴 하지만, 30일 Trial로 사용할 수 있고, 가격은 개인용 버전의 경우 49$이다. (좋은 소프트웨어는 구매하자)

자바스크립트와 웹개발에 최적화 되어 있고, 빠르고 매우 직관적이다. 그리고 Bootstrap과 같은 자바스크립트 프로젝트나, mocha와 같은 자바스크립트 테스트 프레임웍들도 잘 지원한다.REST API를 테스트하기 위한 기능이나 디버깅 기능도 상당히 직관적이라서 어렵지 않게 사용이 가능하다.

  오픈소스를 사용하고 있거나 강의에서 사용할 경우에는 무료 라이센스를 신청할 수 있다.

 



Figure 1. JetBrain社의 자바스크립트, node.js 개발환경인 WebStorm 7





▶ 시스템이 생성하는 객체의 클래스로 시스템을 매개변수화하는 일반적인 방법은 두가지가 있습니다.
1) 객체를 생성하는 클래스를 상속해서 서브클래스를 만드는 방법   <팩토리 메서드>
2) 객체 합성으로 시스템을 매개변수화하는 방법                          <추상 팩토리, 빌더, 원형 패턴>
-> 제품 객체를 생성하는 책임을 갖고 있는 새로운 "팩토리 객체"를 만듭니다.

▶ "그리기 편집기 프레임워크" 를 통해 알아보자.
그리기 편집기 프레임워크는 GraphicTool이 제품 클래스로 매개변수화되는 다양한 방법을 보여준다.

>> 팩토리 메서드를 적용하여, 팔레트에 Graphic의 서브클래스 각각에 대해 GraphicTool의 서브클래스를 생성합니다. GraphicTool은 NewGraphic() 연산은 갖는데, 이 연산은 각 GraphicTool 서브클래스가 재정의합니다.
>> 추상 팩토리 패턴을 적용한 결과, 여러 GraphicFactory의 클래스 계통이 만들어집니다. 클래스 계통은 Graphic 서브클래스 별로 한 개씩입니다. 이때, 각 팩토리는 단지 하나의 제품만을 생성합니다. 예) CircleFactory는 circle, LinFactory는 line을...
>> 원형 패턴을 적용하면 각 Graphic의 서브클래스가 Clone() 연산을 구현하며, GraphicTool은 그것이 생성하는 Graphic의 원형으로 매개변수화 됩니다.


▶ 정리하기
: 팩토리 메서드는 설계를 사용자가 입맛에 맞게 고칠 수 있도록 해 주면서 그 설계가 복잡해지지 않게 합니다. 다른 디자인 패턴은 새로운 클래스가 필요한 반면, 팩토리 메서드 패턴에서는 새로운 연산만 정의하면 됩니다. 개발자들은 객체를 생성하는 표준 방식으로 팩토리 메서드를 자주 사용하고는 합니다. 그러나 인스턴스화 할 클래스가 변하지 않거나 초기화 연산처럼 서브클래스들이 쉽게 재정의 할 수 있는 연산에서 인스턴스화가 된다면 상속으로도 쉽게 해결할 수 있으므로 이때는 꼭 팩토리 메서드를 사용할  필요는 없습니다.
: 추상 팩토리, 원형 또는 빌더 패턴을 사용하는 설계는 팩토리 메서드를 사용하는 설계보다 더 유연할 때가 많습니다. 팩토리 매서드를 사용해서 시작한 설계에 좀 더 유연성을 부가 할 필요가 있다면 다른 생성 패턴을 사용하는 설계로 진화합니다.




1. 단일체(Singleton) 패턴이란?
오직 한 개의 클래스 인스턴스만을 갖도록 보장하고, 이에 대한 전역적인 접근점을 제공합니다. 클래스 자신이 자기의 유일한 인스턴스로 접근하는 방법입니다.
ex) 프린터 스풀, 윈도우 관리자 등.


2. 단일체 패턴은 언제 사용되는가?
- 클래스의 인스턴스가 오직 하나여야 함을 보장하고, 잘 정의된 접근점으로 모든 사용자가 접근할 수 있도록 해야 할 때
- 유일한 인스턴스가 서브클래싱으로 확장되어야 하며, 사용자는 코드의 수정 업이 확장된 서브클래스의 인스턴스를 사용할 수 있어야 할 때


3. 단일체 패턴의 다이어그램


☆ Singleton
: Instance() 연산을 정의하여, 유일한 인스턴스로 접근할 수 있도록 합니다.
  Instance() 연산은 클래스 연산입니다. 유일한 인스턴스를 생성하는 책임을 맡습니다.

4. 단일체 패턴을 쓰면...
1) 유일하게 존재하는 인스턴스로의 접근을 통제합니다.
: Singleton 클래스 자체가 인스턴스를 캡슐화하기 때문에, 이 클래스에서 사용자가 언제, 어떻게 이 인스턴스에 접근 할 수 있는지 제어 할 수 있습니다.

2) 네임스페이스를 좁힙니다.
단일체 패턴은 전역 변수보다 더 좋습니다. 전역 변수를 사용해서 네임스페이스를 망치는 일을 없애주기 때문입니다. 즉, 전역 변수를 정의하여 발생하는 디버깅의 어려움 등 문제를 없앱니다.

3) 연산 및 표현의 정체를 허용합니다.
: Singleton 클래스는 상속될 수 있기 때문에, 이 상속된 서브클래스를 통해서 새로운 인스턴스를 만들 수 있습니다. 또한 이 패턴을 사용하면, 런타임에 필요한 클래스의 인스턴스를 써서 응요프로그램을 구성할 수도 있습니다.

4) 인스턴스의 개수를 변경하기가 자유롭습니다.
: 마음이 바뀌어서 Singleton 클래스의 인스턴스가 하나 이상 존재할 수 있도록 변경해야 할 때도 있는데, 이 작업도 어렵지 않습니다. 게다가, 응용프로그램이 사용하는 인스턴스가 다수여야 할 때도 똑같은 방법을 쓸 수 있습니다.
  즉, Singleton 클래스의 인스턴스에 접근할 수 있는 허용 범위를 결정하는 연산만 변경하면 됩니다. 왜냐하면 기존에는 하나의 인스턴스로만 접근을 허용했다면, 이제는 여러 개의 인스턴스를 생성해서 그 각각의 인스턴스로 접근할 수 있도록 연산의 구현을 바꾸면 되기 때문입니다.

5) 클래스 연산을 사용하는 것보다 훨씬 유연한 방법입니다.
: 단일체 패턴과 동일한 기능을 발휘하는 방법이 클래스 연산을 사용하는 것입니다. 그러나 이 두 언어(C++, 스몰토크)에서 클래스의 인스턴스가 하나 이상 존재할 수 있도록 설계를 변경하는 것은 어려습니다.


cf) 구현방법 中
: 단일체에 대한 레지스트리를 사용하는 것입니다. Instance() 연산에 가능한 Singleton 클래스 집합을 정의하는 대신에 Singleton 클래스는 이 단일체 인스턴스를 레지스트리에 이름을 갖는 인스턴스로 등록합니다.
  레지스트리는 문자열로 정의된 이름을 해당 단일체 인스턴스로 대응시켜 둡니다. Instance() 연산에서 단일체가 필요할 때 레지스트리를 뒤져서 이름으로 해당 단일체를 찾아달라고 의뢰하면 레지스트리는 해당하는 단일체를 찾아서 돌려주는 것입니다. 이런 방식을 취하면 Instance() 연산이 모든 달일체 클래스와 인스턴스를 알 필요가 업습니다.




1. 원형(프토로타입) 패턴이란?
  프로토타입 패턴(prototype pattern)은 생성할 객체들의 타입이 프로토타입인 인스턴스로부터 결정되도록 하며, 인스턴스는 새 객체를 만들기 위해 자신을 복제(clone)하게 된다. 프로토타입 패턴은 추상 팩토리 패턴과는 반대로, 클라이언트 응용 프로그램 코드 내에서 객체 창조자(creator)를 서브클래스(subclass)하는 것을 피할 수 있게 해준다.  프로토타입 패턴은 새로운 객체는 일반적인 방법(예를 들어, new를 사용해서라든지)으로 객체를 생성(create)하는 고유의 비용이 주어진 응용 프로그램 상황에 있어서 불가피하게 매우 클 때, 이 비용을 감내하지 않을 수 있게 해준다. 패턴을 구현하려면, 우선 clone() 메소드를 선언하는 추상 베이스 클래스를 하나 만든다. 다형적 생성자(polymorphic constructor) 기능이 필요한 클래스가 있다면, 그것을 앞에서 만든 클래스를 상속받게 한 후, clone() 메소드 내의 코드를 구현한다.


2. 원형 패턴은 언제 사용되는가?
제품의 생성, 복합, 표현 방법에 독립적인 제품을 만들고자 할 때
- 어떤 클래스의 인스턴스를 만드는 것이 자원/시간을 많이 잡아먹거나 복잡 할 때
- 모두 클래스로 만들기에는 종류가 너무 많은 경우
인스턴스 생성이 어려운 경우(인스턴스화할 클래스를 런타임에 지정할 때, 동적 로딩)- framework와 생성하는 인스턴스를 분리하고 싶은 경우
- 제품 클래스 계통과 병렬적으로 만드는 팩토리 클래스를 피하고 싶을 때
클래스의 인스턴스들이 서로 다른 상태 조합 중에 어느 하나일 때
미리 원형으로 초기화해 두고, 나중에 이를 복제해서 사용하는 것이 매번 필요한 상태 조합의 값들을 수동적으로 초기화하는 것보다 편리 할 수도 있습니다.


3. 원형 패턴의 다이어그램



☆ Prototype
:  자신을 복제하는 데 필요한 인터페이스를 정의합니다.

☆ ConcretePrototype
: 자신을 복제하는 연산을 구현합니다.

☆ Client
: 원형에 자기 자신의 복제를 요청하여 새로운 객체를 생성합니다.


4. 원형 패턴을 쓰면..
1) 런타임에 새로운 제품을 추가하고 삭제할 수 있습니다.
: 원형 패턴을 이용하면 사용자에게 원형으로 생성되는 인스턴스를 등록하는 것만으로도 시스템에 새로운 제품 클래스르 추가할 수 있게 됩니다. 런타임에 새로운 원형을 넣고 빼기가 쉽다는 접에서 다른 생성 패턴에 비해 유연성을 지니고 있습니다.

2) 값들을 다양화함으로써 새로운 객체를 명세합니다.
: 고도로 동적화된 시스템에서는 새로운 클래스를 생성할 필요 없이 객체 합성으로 새로운 행동을 정의할 수 있습니다. 객체의 변수가 다른 클래스에 대한 참조자를 정의하고 있다면, 이 참조자가 합성한 새로운 클래스만 정의하고, 그 클래스에 인스턴스에 대한 참조자만을 넘겨주면, 새로운 행동이 정의되는 것처럼 보인다는 것입니다.

3) 구조를 다양화함으로써 새로운 객체를 명세할 수 있습니다.
: 많은 응용프로그램은 구성요소와 부분 구성요소의 복합을 통해 객체를 구축합니다. 예를 들어, 회로설계를 위한 편집기는 세부 회로를 모아서 큰 회로를 만듭니다. 이런 응용프로그램에서는 편의를 위한 복잡한 사용자 정의 구조를 사용자가 인스턴스화 하여 그 상황에 맞는 세부 회로를 계속 이용할 수 있도록 배려해 줄 때가 많습니다. 복합 회로 객체가 Clone() 연산을 구현함으로써 다른 구조를 갖는 회로의 기본 골격을 만듭니다.

4) 서브클래스의 수를 줄입니다.
: 팩토리 메서드를 보면 Creator 클래스의 계통이 처리할 제품 관련 클래스의 계통과 병렬로 복합되는 것을 알 수 있습니다. 원형 패턴에서는 팩토리 메서드에 새로원 객체를 만들어 달라고 요청하는 것이 아니라 원형을 복제하는 것으로, Creator 클래스에 따른 새로운 상속 계층이 필요 없습니다.

5) 동적으로 클래스에 따라 응용프로그램을 설정할 수 있습니다.
: 몇몇 런타임 환경에서는 동적으로 클래스들을 응용프로그램으로 등록할 수 있도록 해 줍니다. 동적으로 로드된 클래스의 인스턴스를 생성하고 싶은 응용프로그램은 정적으로 그 클래스이 생성자를 참조할 수 없습니다. 그 대신 런타임 환경이 그 클래스의 인스턴스를 자동으로 생성하고 원형 관리자에게 등록합니다. 그러면 응용프로그램은 이 원형 관리자에게서 필요한 클래스의 인스턴스를 얻게 됩니다.


§ 관련 패턴 §
: 원형 패턴과 추상 팩토리 패턴은 어떤 면에서는 경쟁적인 관계입니다. 하지만 함게 사용 될 수도 있습니다. 추상 팩토리 패턴은 원형 집합을 저장하다가 필요할 때 복제하여 제픔 객체를 반환하도록 사용할 수 도 있습니다. 만약 복합체 패턴과 장식자 패턴을 많이 사용해야 하는 설계에서 원형 패턴을 쓰면 종종 재미를 볼 수 있습니다.




1. 빌더(Builder) 패턴이란?
  빌더 패턴이란 복잡한 객체를 생성하는 방법과 표현하는 방법을 정의하는 클래스를 별도로 분리하여, 서로 다른 표현이라도 이를 생성할 수 있는 동일한 절차를 제공할 수 있도록 합니다. 하나의 소스객체에 복잡한 여러개의 객체를 만들 수 있도록 하는 패턴으로 소스 객체는 복잡한 객체를 생성하기 위한 기능을 여러 부분으로 제공합니다.
  즉, 객체를 구성하는 부분을 먼저 생성하고, 이를 조합함으로써 전체 객체를 생성하기 때문에 생성할 객체가 손 쉽게 추가, 확장 가능하게 된다.


2. 빌더는 언제 사용되나?
- 복합 객체의 생성 알고리즘이 이를 합성하는 요소 객체들이 무엇인지 이들의 조립 방법에 독립적일 때
- 합성할 객체들의 표현이 서로 다르더라도 생성 절차에서 이를 지원해야 할 때

§ 예시 - 세트메뉴 서빙 §
  에피타이저 - 메인 - 디저트" 순으로 음식이 제공된다.
  에피타이저 종류는 ○○ 샐러드, ☆☆ 샐러드, □□ 샐러드 ... 가 있고, 메인 메뉴는 ●● 스테이크, ★★ 스테이크, ◆◆ 스테이크 ...가 있다. 마지막 디저트로는 △△ 아이스크림, ♡♡ 아이스크림, ♧♧ 아이스크림 ... 이 있다.
  손님이 원하는 종류는 선택해서 먹을 수 있다. 이처럼 세트 메뉴를 에피타이저 -> 메인 -> 디저트 순으로 음식이 나오지만 그 결과가 달라진다. 이때 bulider 패턴을 사용한다.


3. 빌더 패턴의 다이어그램 
▲ 구조 다이어그램

▲ 상호작용 다이어그램

☆ Builder
: Product 객체의 일부 요소들을 생성하기 위한 추상 인터페이스를 정의합니다.

☆ ConcreteBuilder
: Builder 클래스에 정의된 인퍼페이스를 구현하며, 제품의 부품들을 모아 빌더를 복합니다. 생성한 요소의 표현을 정의하고 관리합니다. 또한 제품을 검색하는데 필요한 인터페이스를 제공합니다.
: 제품의 내부 표현을 구축하고 복합 객체가 어떻게 구성되는지에 관한 절차를 정의합니다.
: 구상 빌더에서는 실제 제품을 만들어서 Product라는 복합 구조에 집어 넣습니다.

☆ Director (Client)
: Builder 인터페이스를 사용하는 객체를 합성합니다.

☆ Product
 : 생성할 복합 객체를 표현합니다.




4. 빌터 패턴을 쓰면....
1) 제품에 대한 내부 표현을 다양하게 변화할 수 있습니다.
  Builder 객체는 디렉터를 제공하고 제품을 복합하기 위해 필요한 추상 인터페이스를 정의합니다. 빌더를 사용하면 제품이 어떤 요소에서 복합되는지, 그리고 각 요소들의 표현 방법이 무엇인지 가릴 수 있게 됩니다. 즉, 어떤 요소로 전체 제품을 복합하고 그 요소들이 어떤 타입들로 구현되는지 알고 있는 쪽은 빌더뿐입니다. 제품을 복합할 때는 빌더에 정의된 추상 인터페이스를 통해 사용자가 동작하기 때문에, 새로운 제품의 표현 방법이나 제품의 복합 방법이 바뀔 때 추상 인터페이스를 정의한 Builder 클래스에서 상속을 통해 새로운 서브클래스를 정의하면 됩니다.

2) 생성과 표현에 필요한 코드를 분리합니다.
  빌더 패턴을 사용하면, 복합 객체를 생성하고 복합 객체의 내부 표현 방법을 별도의 모듈로 정의 할 수 있습니다. 사용자는 제품의 내부 구조를 정의한 클래스는 전혀 모른 채, 빌더와 상호작용을 통해서 필요한 복합 객체를 생성하게 됩니다. 왜냐하면, 이러한 제품 구조에 대한 상세한 정의를 담은 클래스는 클래스에 정의된 어떤 연산의 매개변수로도 정의되지 않기 때문입니다.

3) 복합 객체를 생성하는 절차를 좀 더 세밀하게 나눌 수 있습니다.
  한 번에 복합 객체를 생성하는 것 처럼, 빌더 패턴은 디렉터의 통제 아래 하나의 내부 구성요소들을 만들어 나갑니다. 디렉터가 빌더에서 만든 전체 복합 객체를 되돌려받을 때까지 제품 복합의 과정은 계속됩니다.

4) 클라이언트에서는 추상 인터페이스만 볼 수 있기 때문에 제품은 구현한 코드를 쉽게 바꿀 수 있습니다. 또한 제품의 내부 구조를 보호 할 수 있습니다.

5) 팩토리를 사용하는 경우에 비해 객체를 만들기 위해서 클라이언트에 대해 더 많이 알아야 합니다.

cf) 관련패턴
: 복잡한 객체를 생성할 때 추상 팩토리 패턴은 빌더 패턴과 비슷한 모습을 보입니다. 근복적인 차이가 있다면 빌더 패턴은 복잡한 객체의 단계별 생성에 중점을 둔 반면, 추상 팩토리 패턴은 제품의 유사군들이 존재할 때 유연한 설계에 중점을 둔다는 것입니다. 빌더 패턴은 생성의 마지막 단계에서 생성한 제품을 반환하는 반면, 추상 팩토리 패턴에서는 만드는 즉시 제품을 반환합니다. 추상 팩토리 패턴에서 만드는 제품은 꼭 모여야만 의미 있는 것이 아니라 하나만으로도 의미기 있기 때문입니다.




1. 추상 팩토리(Abstract Factory)란?
  추상 팩토리 패턴(Abstract factory pattern)은 다양한 구성 요소 별로 '객체의 집합'을 생성해야 할 때 유용합니다. 이 패턴을 사용하여 상황에 알맞은 객체를 생성할 수 있습니다.
  추상 팩토리를 통해서 제품군(객체의 집합)을 생성하기 위한 인터페이스를 제공할 수 있습니다. 인터페이스를 이용하는 코드를 만들면 코드를 제품을 생산하는 실제 팩토리와 분리 시킬 수 있습니다. 서로 다른 상황별로 적당한 제품을 생산할 수 있는 다양한 팩토리를 구현할 수 있게 됩니다.
  즉, 공통된 부분은 객체들의 동적 메모리 할당을 책임지고 관리하는 팩토리를 만들어서 확장 및 관리를 용이하게 할 수 있게 하는 패턴입니다.인터페이스를 이용하여 서로 연관된, 또는 의존하는 객체를 구상 클래스를 지정하지 않도고 생성할 수 있습니다.


2. 추상 팩토리는 언제 사용되나?
- 여러 객체군들 중에서 특정 객체군을 선택하여 생성하고자 할 때
- 관련된 제품 객체들이 함께 사용되도록 설계되어서, 이 부분에 대한 규약이 외부에서 사용할 시에도 지켜지게 하고 싶을 때
- 객체가 생성되거나 구성/표현되는 방식과 무관하게 시스템을 독립적으로 만들고자 할 때
- 여러 제품군 중 하나를 선택해서 시스템을 설정해야 하고 한번 구성한 제품을 다른 것으로 대체할 수 있을 때
- 제품에 대한 클래스 라이브러리를 제공하고, 그들의 구현이 아닌 인터페이스를 노출시키고 싶을 때


3. 추상 팩토리 패턴의 다이어그램



☆ AbstractFactory 인터페이스
: 모든 구상 팩토리에서 구현해야 하는 인터페이스입니다. 제품을 생산하기 위한 일련의 메소드들이 정의되어 있습니다.

☆ AbstractProducetA 인터페이스
: 제품군으로 각  구상 팩토리에서 필요한 제품들을 모두 만들 수 있습니다.

☆ Client
: 클라이언트를 만들 때는 추상 팩토리를 바탕으로 만듭니다. 실제 팩토리는 실행시에 결정됩니다.

☆ ConcreateFactory 1/2
: 구상 팩토리에서는 서로 다른 제품군을 구현합니다. 클라이언트에서 제품이 필요하면 이 팩토리 가운데 적당할 걸 골라서 쓰면 되기 때문에 제품 객체의 인스턴스를 직접 만들 필요가 없게됩니다.

☆ ConcreateProduct A/B
:  구체적으로 팩토리가 생성할 객체를 정의하고, AbstractProduct가 정의하는 인터페이스를 구현합니다.


§ 협력방법 §
- 일반적으로 ConcreteFactory 클래스의 인스턴스 한 개가 런타임에 만들어집니다. 이 concreate factory는 어떤 특정 구현을 갖는 제품 객체를 생성합니다. 서로 다른 제품 객체를 생성하려면 사용자는 서로 다른 concreate factory를 사용해야 합니다.
- AbstractFactory는 필요한 제품 객체르르 생성하는 책임을 ConcreateFactory 서브 클래스에 위임합니다.


4. 추상 팩초리 패턴을 쓰면....
1) 구체적인 클래스를 분리합니다.
  추상 팩토리 패턴을 쓰면 응용프로그램이 생성 할 각 객체의 클래스를 제어할 수 있습니다. 팩토리는 제품 객체를 생성하는 과정과 책임을 캡슐화한 것이기 때문에, 구체적인 구현 클래스가 사용자에게서 분리됩니다. 일반 프로그램은 추상 인터페이스를 통해서만 인스턴스를 조작합니다. 제품 클래스 이름이 구체 팩토리의 구현에 분리되므로, 사용자 코드에는 나타나지 않는 것입니다.

2) 제품군을 쉽게 대체할 수 있습니다.
  구체 팩토리의 클래스는 응용프로그램에서 한 번만 나타나기 때문에 응용프로그램이 사용할 구체 팩토리를 변경하기는 쉽습니다. 또한, 구체 팩토리를 변경함르오써 응용프로그램은 서로 다른 제품을 사용할 수 있게 변경됩니다. 추상 팩토리는 필요한 모든 것을 생성하기 때문에 전체 제품군은 한번에 변경이 가능합니다.

3) 제품 사이의 일관성을 증진시킵니다.
  하나의 군 안에 속한 제품 객체들이 함께 동작하도록 설계되어 있을 때, 응용프로그램은 한 번에 오직 한 군에서 만든 객체를 사용하도록 함으로써 프로그램은 한 번에 오직 한 군데에서 만든 객체를 사용하도록 함으로써 프로그램의 일관성을 갖도록 해야 합니다.

4) 새로운 종류의 제품을 제공하기 어렵습니다.
  새로운 종류의 제품을 만들기 위해 기존 추상 팩토리를 확장하기가 쉽지 않습니다. 생성되는 제품은 추상 팩토리가 생성할 수 있는 제품 집합에만 고정되어 있기 때문입니다. 만약 새로운 종류의 제품이 등장하면 팩토리의 구현을 변경해야 합니다. 이는 추상 팩토리와 모든 서브클래스의 변경을 가져옵니다. 즉, 인터페이스가 변경되는 새로운 제품을 생성하는 연산이 추가되거나, 기존 연산의 반환 객체 타입이 변경되었으므로, 이를 상속받는 서브클래스 모두 변경되어야 합니다.

cf) 관련패턴
: AbstractFactory 클래스는 팩토리 메서드 패턴을 이용해서 구현되는데, 원형 패턴을 이용할 때도 있습니다. 구체 팩토리는 단일체 패턴을 이용해 구현하는 경우가 많습니다.




1. 생성 패턴(Creational pattern)이란?
 인스턴스를 만드는 절차를 추상화하는 패턴입니다. 이 범주에 해당하는 패턴은 객체를 생성&합성하는 방법이나 객체의 표현 방법과 시스템을 분리해 줍니다. 클래스 생성 패턴이 인스턴스로 만들 클래스를 다양하게 만들기 위한 용도로 상속을 사용하는 반면, 객체 생성 패턴은 인스턴스화 작업을 다른 객체에게 떠넘길 수 도 있습니다.
 생성 패턴은 시스템이 어떤 구체 클래스를 사용하지에 대한 정보를 캡슐화합니다. 그리고 생성 패턴은 이들 클래스의 인스턴스들이 어떻게 만들고 어떻게 서로 맞붙는지에 대한 부분을 완전히 가려줍니나. 결론적으로, 생성 패턴을 이용하면 무엇이 생성되고, 누가 이것을 생성하며, 이것이 어떻게 생성되는지, 언제 생성할 것인지 결정하는데 유연성을 확보할 수 있게 됩니다.

2. 예제로 보는 패턴들....
[[ 미로게임 ]]
§ 전제
- 단순히 미로에서 빠져나오는 게임일 때는 전체 미로 중 플레이어에게 보이는 만큼의 미로가 표시 됨.
- 풀어야 할 문제가 있을 수도 있고, 극복해야 할 위험이 숨겨진 미로게임일 때는 미로의 일부분에 해당하는 평면 지도가 제공되기도 함.
- 복잡한 미로게임을 다루지는 않음.
- 플레이어가 ( 1..* )임.
- 미로는 방들의 집합이고 각 방은 옆에 무엇이 있는지도 알 수 있음.
- 방 옆에 방
- 방 옆에 문
- 방 옆에 벽

§ 클래스도

( C++  구현시 )
- 각 방은 네 개의 뱡향을 갖는데,,,
MapSite 클래스는 미로의 구성요소들에 필요한 모든 연산을 정의한 공통 추상 클래스
 
Room 클래스는 MapSite를 상속받은 구체적인 클래스로 미로에 있는 다른 요소와 관련성을 갖도록 정의합니다. 
Door과 Wall 클래스
- 또한 방들의 집합을 표현하기 위해서 클래스 Maze를 정의

-  MazeGame이란 클래스가 필요합니다.
   실제로 미로를 생성하는 클래스로 일련의 연산을 통해 빈 미로에 미로의 구성요소를 추가하고 이들을 연결하는 것입니다.

위 CreateMaze()가 갖고 있는 문제는 유연성이 떨어진다는 것이다. 즉, Room 클래스의 생성자에 변경되는 아래 부분만 코드화하면 된다!
r1->SetSide(East, theDoor);
r2->SetSide(West, theDoor);
(흠... 위 소스코드는 타이핑 하는데.. 자연스럽게.. Ctrl+C / Ctrl+V 를 이용하고 있는 제 자신을 발견하고...놀랐다는;;)
생성패턴은 이런 상황에서 어떻게 유연한 설계를 할 수 있는지에 대한 해법을 제공합니다.


지금 시점에서 가장 큰 장애 요인은 클래스들의 인스턴스를 직접 생성하도록 하드코딩한다는 점입니다.
- CreateMaze가 방, 벽, 문을 생성하기 위해서 생성자를 이용하지 않고 가상 함수를 호출하도록 구현되어 있다면, 이 가상 함수의 실제구현을 다양한 방법으로 변경할 수 있을 것입니다. <<팩토리 메소드 패턴>>
- CreateMaze가 방, 벽, 문을 생성하기 위해 생성 방법을 알고 있는 객체를 매개변수로 넘겨받을 수 있다면, 생성 방법이 바뀔 때 마다 새로운 매개변수를 넘겨받음으로써 생성할 객체의 유형을 달리할 수 있습니다. <<추상 팩토리 메소드 패턴>>
- CreateMaze가 생성하고자 하는 미로에 방, 문, 벽을 추가하는 연산을 사용해서 새로운 미로를 만들 수 있는 객체를 넘겨받는다면 미로를 만드는 방법이나 변경을 이 객체의 상속을 통해서 해결할 수 있습니다. <<빌더 패턴>>
- CreateMaze를 이미 만든 다양한 방, 문, 벽 객체로 매개변수화하는 방법도 가능한데, 이미 만든 객체를 복사해서 미로에 추가하면, 이들 인스턴스를 교체하여 미로의 복합 방법을 변경할 수 있습니다. <원형 패턴>

cf) 단일체 패턴은 한 게임에 오로지 하나의 미로 객체만 존재할 수 있고 그 게임에서 돌아가는 모든 게임 객체들이 이 미로에 접근이 가능하도록 보장합니다. 전역 변수나 전역 함수에 의존할 필요 없이 이런 일이 가능합니다. 또한 단일체 패턴은 기존 코드를 건드리지 않고도 미로를 쉽게 대체하거나 확장할 수 있도록 해 줍니다.




0. 시작하기
 설계는 지금 당장 갖고 있는 문제를 해결할 수 있어야 하지만, 나중에 생길 수 있는 문제나 추가된 요구 사항들도 수용할 수 있도록 일반적이고 포괄적이어야 합니다. 즉, 재설계를 하지 않아도 다시 사용할 수 있어야 하고, 아니면 가능한 최소한의 수정을 통해서 다시 사용할 수 있는 설계여야 합니다.

1. 디자인 패턴이란?
 디자인 패턴은 "특정한 전후 관계에서 일반적 설계 문제를 해결하기 위해 상호교류하는 수정 가능한 객체와 클래스들에 대한 설명"입니다.
 디자인 패턴은 설계자로 하여금 재사용이 가능한 설계는 선택하고, 재사용을 방해하는 설계는 배제하도록 도와주며, 패턴을 쓰면 이미 만든 시스템의 유지보수나 문서화도 개선할 수 있고, 클래스의 명세도 정확하게 할 수 있으며, 객체 간의 상호작용 또는 설계의 의도 등까지 명확하게 정의할 수 있습니다.

▷  생성 패턴은 객체의 생성 과정에 관여하는 것
생성 클래스 패턴은 객체를 생성하는 책임의 일부를 서브클래스가 담당
생성 객체 패턴은 이를 다른 객체에게 위임.
▷ 구조 패턴은 클래스나 객체의 합성에 관한 것
구조 클래스 패턴은 상속을 이용해서 클래스를 복합
구조 객체 패턴은 객체를 합성하는 방법을 정의
▷ 행동 패턴은 클래스나 객체들의 상호작용하는 방법과 책임을 분산하는 방법을 정의
행동 클래스 패턴은 상속을 이용해서 알고리즘과 제어 흐름을 기술
행동 객체 패턴은 하나의 작업을 수행하기 위해 객체 집합이 어떻게 협력하는지를 기술

    

목적
생성
구조
행동

범위
클래스
팩토리 메서드
(Factory Method)
적응자(Adapter class)
해석자(Interpreter)
템플릿 메서드
(Template Method)
객체
추상 팩토리(Abstract Factory)
빌더(Builder)
원형()
단일체
적응자(Adapter object)
가교(Bridge)
복합체(Composite)
장식자(Decorator)
퍼사드(Facade)
플라이급(Flyweight)
프록시(Proxy)
책임 연쇄
(Chain of Responsibilty)
명령(Command)
해석자(Interpreter)
중재자(Mediator)
반복자(Iterator)
메멘토(Memento)
감시자(Observer)
상태(State)
전략(Strategy)
방문자(Visitor)

<표1> 디자인 패턴 영역


<그림 1> 디자인 패턴 관계도

2. 디자인 패턴이 필요한 이유?
1) 특정 클래스에서 객체 생성
 객체를 생성할 때 클래스 이름을 명시하면 어떤 특정 인터페이스가 아닌 어떤 특정 구현에 종속됩니다. 이런 종속은 앞으로의 변화를 수용하지 못합니다. 이를 방지하려면 객체를 직접 생성해서는 안됩니다.
(디자인 패턴 : 추상 팩토리, 팩토리 메서드, 원형)

2) 특정 연산에 대한 의존성
 특정한 연산을 사용하면, 요청을 만족하는 한 가지 방법에만 매이게 됩니다. 요청의 처리 방법을 직접 코딩하는 방법을 피하면, 컴파일 시점과 런타임 모두를 만좃하면서 요청 처리 방법을 쉽게 변경할 수 있습니다.
(디자인 패턴 : 책임 연쇄, 명령)

3) 하드웨어와 소프트웨어 플랫폼에 대한 의존성
 기존에 존재하는 시스템 인터페이스와 응용프로그래램 프로그래밍 인터페이스는 소프트웨어 및 하드웨어 플랫폼마다 모두 다릅니다. 특정 플랫폼에 종속된 소프트웨어는 다른 플랫폼에 이식하기도 어렵고요. 또한 본래의 플랫폼에서도 버전의 변경을 따라가기 어려울 수 도 있습니다. 이런 플랫폼 종속성을 제거하는 것은 시스템 설계에 있어 매우 중요합니다,.
(디자인 패턴 : 추상 팩토리, 가교)

4) 객체의 표현이나 구현에 대한 의존성
 사용자가 객체의 표현 방법, 저장 방법, 구현 방법, 존재의 위치에 대한 모든 방법을 알고 있다면 객체를 변경할 때 사용자도 함"께 변경해야 합니다. 이런 정보를 사용자에게 감춤으로써 변화의 파급을 막을 수 있습니다.
(디자인 패턴 : 추상 팩토리, 가교, 메멘토, 프록시)

5) 알고리즘 의존성
 알고리즘 자체를 확장할 수도, 최적화할 수도, 다른 것으로 대체할 수도 있는데, 알고리즘에 종속된 객체라면 알고리즘이 변할 때마다 객체도 변경해야 합니다. 그러므로 변경이 가능한 알고리즘은 분리해 내는 것이 바람직합니다.
(디자인 패턴 : 빌더, 반복자, 전략, 템플리 메서드, 방문자)

6) 높은 결합도
 높은 결합도를 갖는 클래스들은 독립적으로 재사용하기 어렵습니다. 높은 결합도를 갖데 되면 하나의 커다란 시스템이 되어 버립니다. 이렇게 되면 클래스 하나르 수정하기 위해서 전체를 이해해야 하고 다른 많은 클래스도 변경해야 합니다. 또한 시스템은 배우기도 힘들고, 이식은 커녕 유지보수하기 조차도 어려운 공룡이 되어 버립니다.
 약한 결합도는 클래스 자체의 재사용을 가능하게 하고 시스템의 이해와 수정, 확장이 용이해서 이식성을 증대시킵니다. 추상 클래스 수준에서 결합도를 정희한다거나 계층화시키는 방법으로 디자인 패턴은 낮은 결합도의 시스템을 만들도록 합니다.
(디자인 패턴 : 추상 팩토리, 가교, 책임 연쇄, 명령, 퍼사드, 중재자, 감시자)

7) 서브 클래싱을 통한 기능 확장
 객체 합성과 위임은 행동 조합을 위한 상속보다 훨씬 유연한 방법입니다. 기존 객체들을 새로운 방식으로 조합함으로써 새로운 서브클래스를 정의하지 않고도 응용프로그램에 새로운 기능성을 추가할 수 있습니다. 한편, 객체 합성을 많이 사용한 시스템은 이해하기가 어려워집니다. 많은 디자인 패턴에서는 그냥 서브클래스를 정의하고 다른 인스턴스와 새로 정의한 클래스의 인스턴스를 합성해서 기능을 재정의하는 방법을 도입합니다.
(디자인 패턴 : 가교, 책임 연쇄, 장식자, 감시자 , 전력)

8) 클래스 변경이 편하지 못한 점
 가끔 클래스를 변경하는 작업이 그렇게 단순하지 않을 때가 많습니다. 소스 코드가 필요한데 없다고 가정해 봅시다. 또한 어떤 변경을 하면 기존 서브클래스의 다수를 수정해야 한다고 가정합시다. 디자인 패턴은 이런 환경에서 클래스를 수정하는 방법을 제시합니다.
(디자인 패턴 : 적응자, 장식자, 방문자)

3. 디자인 패턴을 고르는 방법
- 패턴이 어떻게 문재를 해결하는지 파악합시다.
- 패턴의 의도 부분을 봅시다.
- 패턴들 간의 관련성을 파악합시다.
- 비슷한 목적의 패턴들을 모사어 공부합시다.
- 재설꼐의 원인을 파악합시다.
- 설계에서 가변성을 가져야 하는 부분이 무엇인지 파악합시다.

4. 디자인 패턴을 통해 다양화 할 수 있는 설계 측면

 목적
디자인 패턴  
이 패턴을 통해 다양화 할 수 있는 부분
생성
 추상 팩토리 (Abstract Factory)
 제품 객체군
 빌더(Builder)
 복합 객체 생성 방법
 팩초리 메서드(Factory Method)
 인스턴스화 될 객체의 서브클래스
 원형(Prototype)
 인스턴스화 될 객체의 클래스
 단일체(Singleton)
 클래스의 인스턴스가 하나일 때
구조
 적응자(Adapter)
 객체에 대한 인터페이스
 가교(Bridge)
 객체 구현
 복합체(Composite)
 객체의 합성과 구조
 장식자(Decorator)
 서브클래싱 없이 객체의 책임성
 퍼사드(Facade)
 서브시스템에 대한 인터페이스
 플라이급(Flyweight)
 객체의 저장 비용
 프록시(Proxy)
 객체 접근 비용
행동
 책임 연쇄(Chain of Responsibility)
 요청을 처리하는 객체
 명령(Command)
 요청을 처리 시점과 처리 방법  
 해석자(Interpreter)
 언어의 문법과 해석 방법
 반복자(Iterator)
 집합 객체 요소들의 접근 방법 및 순회 방법
 중재자(Mediator)
 어떤 객체들이 어떻게 상호작용하는지
 메멘토(Memento)
 어제 어떤 정보를 객체의 외부에 저장하는지
 감시자(Observer)
 다른 객체의 종속적인 객체 수
 종속적인 객체들의 상태 변경 방법
 상태(State)
 객체의 상태
 전략(Strategy)
 알고리즘
 템플릿 메소드(Template Method)
 알고리즘 단계   
 방문자(Visitor)
 클래스의 변경 없이 객체에 적용할 수 있는 연산

<표2> 디자인 패턴을 통해 다양화 할 수 있는 설계 측면




드디어 Class강좌를 쓰고 있자니 마음이 설레네요!
언제나 화이팅!

*이 강좌는 C언어를 끝냈다는 가정하에 실시합니다.

┌───────────────┐
---앞으로의 목차---
3-2. 객체에 대하여
3-3. 접근제어
3-4. 멤버함수의 외부정의
└───────────────┘

<지난 강좌를 살펴보고 와주세요 !! : http://blog.naver.com/owndks98o/120157307983 >

3-2. 객체에 대하여
이번시간에는 객체에 대한 이모저모를 알아보겠습니다.
어쩌면 상당히 따분한 이론수업이 될 수도 있으나, 객체의 기본을 다루는 꼭 필요한 부분이니
잘 익혀 두시기를 바랍니다.

먼저 데이터 추상화(Data Abstraction) 를 알아보도록 하겠습니다.
원래 지향하는 바라면, 제가 비유까지 해야 하나 워낙 난해한 부분이라 이 책의 내용을 인용하겠습니다.
(전 C++을 "열혈강의 C++프로그래밍"과 "누드 C++"에서 참고하였습니다.)

여러인디언이 있습니다. 문제는 그중에 단 한명만이 코끼리를 본적이 있기에, 그 인디언은 다른 인디언들에게 코끼리의 모양에 대해 설명해 주기 시작합니다.
"코끼리는 말이야. 일단 발이 네 개야. 그리고 코가 하나 있는데, 그 코의 길이가 한 5미터 정도는 되지. 그리고 그 코를 이용해서 목욕을 하기도 하고, 또 물건을 집기도 해. 아! 크기는 말이야. 글쎄 무개로 따지면 1톤은 족히 넘을 거야"

이 설명을 들은 인디언들은 이 코끼리를 머릿속에 정리할것입니다. 이렇게 말이죠!
  1. 발이 4개
  2. 코의 길이가 5미터 정도
  3. 몸무게 1톤정도
  4. 코를 이용하여 목욕
  5. 코를 이용하여 물건을 집음
이것을 프로그래밍에 비유하면 1,2,3 번은 데이터 적인 측면, 4,5번은 기능적인 측면입니다.
이렇듯,
"현실세계의 사물을 데이터적인 측면과 기능적 측면을 통해서 정의하는것"
이 데이터추상화(Data Abstraction)이라고 합니다.

그럼 이제 하나의 객체(Object)에 대해 프로그래밍에서 사용하기까지의 과정에 대한 용어를 알아보죠.

예를 들어, 먼저 "사람"이란 것을 프로그램 상에 옮길때에, 데이터 추상화를 하는 과정을 "추상화" 라고 합니다.
(갑자기 "사람"이란 단어가 너무나도 어색하게 느껴지는 군요;;)

 

그리고, 이 추상화한 것을 자료형으로 정의하는 것을 "클래스화"라고 합니다.

이것이 일반적으로 클래스를 정의할때에 사용되는 용어입니다.

클래스를 정의한다는 것은 일반적인 자료형(int,char,...)등을 정의하는 것과 같습니다.
따라서 클래스를 사용할떄에 클래스를 선언해줄 필요가 있습니다.
따라서, 이렇듯 클래스를 선언해주는 것을 "인스턴스화(instantiation)"한다 라고 표현합니다.


이번시간에는 여러 클래스에 대한 용어를 알아보았습니다.
다음강에서 만나도록 합시다~~!!




C++의 첫이름이 뭔지 아시나요?

 C with Class 였습니다.
그만큼 Class의 비중은 C++ 에서 크게 차지합니다.

그 Class의 시작을 향해!!

*이 강좌는 C언어를 끝냈다는 가정하에 실시합니다.

┌───────────────┐
---앞으로의 목차---
3-1. 구조체? 클래스?
3-2. 객체에 대하여
3-3. 접근제어
└───────────────┘

<지난 강좌를 살펴보고 와주세요 !! : http://blog.naver.com/owndks98o/120156950445 >

3-1. 구조체? 클래스?
클래스에 대해 이해하려면, 클래스의 Downgrade 버젼이라고 말할수 있는 구조체와의 연관이 필요합니다.
그러니 잠시 구조체에 대한 이야기를 하고 지나가 보죠.

구조체는 그 이름 그대로 구조적인 프로그래밍을 위해 태어났습니다.
프로그램이 커지며, 변수가 많아지고 그 변수들의 관리가 힘들어지기에, 그 변수들을 몇가지 기준에 따라 분류한 것이 구조체입니다.
따라서 구조체는 관련된 데이터를 묶기에도, 그 프로그래밍에도 편리하다 는 장점이 있습니다.

C++에는 이러한 구조체의 기능에도 +를 더해줍니다.
일반적인 C언어라면 아래와 같이 구조체를 정의할 것입니다.

typedef struct _Leanix{
char name[10];
int age;
}Leanix;

Leanix nx;

하지만 C++은 사용자가 정의했든, 언어자체적으로 정의했든 동일하게 대우해주자는 철학이 있습니다. 따라서,

struct Leanix{
char name[10];
int age;
};

Leanix nx;

처럼 정의하여도 오류가 나지 않습니다.

프로그램은, 흔히들 아래와 같이 이루어져 있다고 이야기합니다.
프로그램 = 자료구조 + 알고리즘
어렵게 느껴지신다고요?

그냥 변수와 그 변수를 관리하는 연산으로 이루어져 있다는 뜻입니다.

/*
StructAndFunction.cpp
*/
#include
using namespace std;

struct Dat{
int ndat;
char cdat;
};

void Set(Dat& dat,int nDat,char cDat){
dat.ndat=nDat;
dat.cdat=cDat;
}

void Init(Dat& dat){
dat.ndat=dat.cdat=0;
}

int main(){
Dat d;
Init(d);
Set(d,10,'d');
return 0;
}

위 소스에 비유하면, 구조체는 자료구조이고 함수는 알고리즘이 되는 것이죠.
하지만 이소스를 보면 영 거슬리는 부분이 있습니다.
왜 꼭 Dat함수의 레퍼런스를 넘겨야 하는 것일까요?
분명 Set과 Init는 구조체 Dat의 함수인데 왜 밖에 따로 선언되어있는 것일까요?

그러니 그냥 묶어 버립시다.
/*
StructOnly.cpp
*/
#include
using namespace std;

struct Dat{
void Set(int nDat,char cDat){
ndat=nDat;
cdat=cDat;
}
void Init(){
ndat=cdat=0;
}
int ndat;
char cdat;
};
int main(){
Dat d;
d.Init();
d.Set(10,'d');
return 0;
}
놀라운가요? 아직은 간단하게 이해합시다. Dat이라는 구조체 안에 함수가 존재하는 것이라고.
간단하죠? 그냥 함수를 구조체 안에 넣은것에 지나지 않습니다.

더욱 놀라운 것은, 이젠 Dat이 구조체가 아닌, 클래스라는 사실입니다.

"아니, struct를 사용했는데 클래스라고?" 라고 따지는 분이 있겠지요? 그럼,
"구조체 안에 함수가 있을수 있나요?" 라고 묻겠습니다.

즉 Dat은 클래스가 되는 것이며, 위의 빨간 부분에서 말했듯이,
"Class(클래스)=Attribute(특성-변수-) + Method(방법-함수-)"
가 되는 것입니다.
보통 Attribute를 가르켜 멤버변수라고 하며, Method를 가르켜 멤버함수라고 합니다.

그럼 이제 Dat을 완벽히 클래스로 바꿔봅시다.
/*
CDat.cpp
*/
#include
using namespace std;

class Dat{
public:
int ndat;
char cdat;
void Set(int nDat,int cDat){
ndat=nDat;
cdat=cDat;
}
void Init(){
ndat=cdat=0;
}
};
int main(){
Dat d;
d.Init();
d.Set(10,'d');
cout<<"ndat : "<
return 0;
}

어엇 아직은 모르는 부분이 남아있습니다. public: 등에 관한 것이지요.
서서히 배울테니 걱정마시기 바랍니다.

그리고 이젠, 클래스를 '객체' 라고 표현합니다.
하나의 완전한 대상체라고 여기는 것이죠.

그럼 다음강의에서 뵙도록 하죠!!


+ Recent posts