직접 관할함으로써 혁신에 대한 영감을 찾을 수 있다.
하지만 숱한 삶의 길목에서 당신은 아주 기계적으로,
무의식적으로 그 기회를 스쳐 지나가버리고 만다.
그러면 영감을 만나지 못한다.
당신이 밟고 다니던 길을 벗어나라.
그러면 발견할 수 있는 기회가 훨씬 더 많아진다.
여행, 특히 해외여행을 하거나,
새로운 운동을 시도하거나
새로운 활동을 경험할 때 그런 계기가 생긴다.
이런 때 당신은 마음을 좀 더 열고 어린이처럼 질문한다.
"왜 그럴까?" "왜 안 될까?"
이 같은 질문은 당신을 혁신으로 인도한다.
당신이 새로운 것을 경험할 때마다 신중하게 주의를 기울이고
인상, 반응, 의문등을 메모해야 한다.
특히 당신을 괴롭히는 문제를 더욱 주도면밀하게 써 놓아야 한다.
우리는 이런 메모를 '결점 리스트'라고 부른다.
그 리스트는 당신의 인생을 바꿀 수 있다.
숱한 기업들이 일상적인 일로 사람들이 허우적거리는 것을 관찰하면서,
그 문제를 어떻게 해결할까 궁리하고 있다.
이런 기횐느 바로 당신에게도 있다는 걸 잊지 마라
* 문제 사례 설명
- 예제
- 웹으로 게시판 서비스를 제공하는 프로그램을 작성한다고 가정
- 이 때 게시판 프로그램은 CGI(Common Gateway Interface) 형태로 작성
- 웹 브라우저로부터 전달된 요청이 웹 서버를 거쳐 표준 입력 형태로 게시판 프로그램에 전달
- 게시판 프로그램에서 표준 출력 형태로 전송한 결과가 웹 서버를 거쳐 이용자가 보는 웹 브라우저의 화면으로 전달되는 형태
- 이 때 웹 브라우저로부터 전달되는 요청의 종류는 "cmd=login"과 같이 cmd라는 이름의 값으로 지정되는 문자열에 의하여
- 여기서 문제는 게시판에서 제공하는 서비스 항목이 처음부터 명확해지지 않고 개발도중에 점차 추가될 가능성이 많음
- 예를 들어 처음에는 이용자 로그인과 게시물 목록 보여주기, 게시문 본문 읽기 서비스 항목만 있다가
- 점차 게시물 쓰기, 게시물 추천하기 등의 서비스 항목이 추가
- 이럴 경우 어떻게 하면 기존에 개발해 두었던 부분들을 수정하지 않고 쉽게 새로운 서비스 항목을 추가할 수 있는가?
* 다양한 접근 방법 및 Command 패턴
- CGI 형태로 게시판 프로그램을 작성할 때 게시판에서 제공하는 서비스 항목을 쉽게 추가할 수 있도록 설계
- 여기서 서비스 항목이 추가된다는 것은 뒤집어 생각하면 게시판 프로그램으로 전달되는 요청의 종류가 추가
- 이는 곧 요청에 따라 처리해야 할 작업이 추가
- 주어진 문제는 게시판 프로그램에 새로운 요청 처리를 수행하는 작업을 수시로 쉽게 추가하려면 어떤 구조의 설계를 하는 것이 좋은가?
Command Pattern 구현 관련 사항
- Execute() 멤버 함수의 구현에 대해 생각해보면
단순히 요청을 처리할 객체의 멤버 함수를 호출하는 형태부터
요청 자체를 직접 처리하는 형태까지 다양할 수 있다
- 이 때 후자 방식은 Command 클래스가 다른 클래스에 의존하지 않게 구현 하고 싶을 때나 요청 처리를 수행할 적당한 객체가 없을 때 또는
작업 수행과 관련된 객체를 묵시적으로 알고 있을 때 유용
* 직접 처리하는 경우의 문제점
- 클라이언트 프로그램이 요청을 처리할 객체를 일일이 알고 있어야 함
- 새로운 종류의 요청 처리가 필요할 때마다 Client 프로그램을 수정
1. 클라이언트 프로그램이 요청을 처리할 객체를 일일이 알 필요가 없는 방법
- 요청을 처리하는 객체들의 클래스를 모두 동일한 상속 구조에 포함
- 여기서 클래스들을 동일한 상속 구조에 포함시켜 정의하는 것인 각 클래스들이 동일한 인터페이스를 가지도록 만드는 것
- 이렇게 되면 클라이언트는 처리해야 할 요청의 종류에 상관 없이 동일한 형태로 프로그램 작성이 가능
- 그러나 이 방법은 요청을 처리하는 객체들의 클래스가 별다른 관련도 없는데 같은 상속 구조 하에서 동일한 자료형으로 다루어지게 만드는 것
- 또 다른 방법
- 클라이언트가 하던 역할을 대신하는 객체를 두는 것
- 요청의 종류에 따라 처리 객체를 지정하는 일을 대신 수행하는 객체를 정의하고 클라이언트가 하던 역할을 모두 이 객체에게 위임
- 이 방법을 적용할 경우 클라이언트는 당연히 요청을 처리할 객체에 대해 일일이 몰라도 됨
- 왜냐하면 그 일을 위임받은 객체가 따로 존재하기 때문
- 그렇다면 이 때 클라이언트의 역할을 위임받은 객체의 클래스는 실제 어떻게 설계되는 것이 좋은가?
- 문제의 핵심은 요청의 종류에 따라 그것을 처리할 객체에 대한 정보를 저장, 관리하도록 만드는 것
- 이보다 좋은 방법은 요청의 종류 별로 별도의 클래스를 정의해서 그것을 처리할 객체에 대한 정보를 저장, 관리
- 단, 이때 클라이언트 프로그램에서 이들 클래스 객체들을 동일한 방식을 다룰 수 있게 만들어 주기 위해서는 이들 클래스의 상위에 Command 클래스와 같은 추상 클래스를 정의해주는 것이 필요
- 새로운 요청이 추가되더라도 클라이언트가 수정되지 않게 하는 방법
- 클라이언트가 수정되지 않게 만들려면 존재하는 조건 비교 문장이 사라짐
- 주어질 수 있는 값들과 그에 따라 실행해야 할 모듈들을 미리 등록해두었다가 요청이 들어오면 일치하는 모듈을 찾아서 곧바로 찾아서 실행
- 이 방법을 적용하려면 실행해야 할 모듈들을 일반화시켜 저장, 관리할 수 있는 자료형
- 한 가지 방법은 동일한 상속 구조 하에 정의, 각 인터페이스 명을 통일
- 불려질 모듈 별로 각각 별도의 클래스를 정의하고 이들이 동일한 상속 구조에 놓임
- 결국 별도의 클래스 상속 구조를 정의해서 활용
* Execute( ) 멤버 함수로 전달되어야 할 인자가 클래스마다 다를 경우
1. 각 클래스의 생성자의 인자로
Execute( ) 멤버 함수에서 사용할 인자를 미리 전달
요청을 처리할 객체가 각 클래스마다 다르므로,
생성자를 통해 미리 요청을 처리할 객체를 전달
2. Execute( ) 멤버 함수의 인자로 주어질 것들을 각각 클래스로 정의하고,
이들의 상위에 추상클래스를 정의함으로써
Execute( ) 멤버 함수가 동일한 자료형의 인자를 가지도록 만드는 방식
Execute( ) 멤버 함수로 전달되는 인자를 Request 클래스로 정의한 것
void Execute(Request& request);
* 여러 작업을 한꺼번에 처리할 수 있는 방법
- 삭제 후 삭제된 게시물의 목록 보여주기
DeleteCommand( )
ListCommand( )
- MacroCommand 패턴을 이용
* 새로운 요청이 추가될 때마다
Command의 하위 클래스를 매번 새로 생성하지 않고 실행할 수 있는 방법
- C++의 template 기법
template <typename Type>
class Command{
public:
void Execute(Request& request){
m_object->DoAction(request);
}
private:
Type* m_object;
};
다만 이 경우, 요청을 처리하는 객체의 인터페이스가 DoAction( ) 형태 통일
* Template Functor 방식
- 각 요청에 대한 처리 모듈을 미리 등록해두되, Command 패턴에서처럼
작업을 처리할 객체와 작업 처리 모듈을 감싸주기 위한 클래스를
요청의 종류마다 각각 정의하지 말고, Functor라는 클래스를 이용
- 여기서 Functor 클래스는 실제 작업 처리 모듈에 대한 함수 포인터를 내부 적으로 가지고 있는 것
- 작업 처리 모듈이 객체의 멤버 함수일 경우에는 객체에 대한 참조 값과
멤버 함수에 대한 포인터를 같이 저장, 관리할 수 있게 설계된 것
- 이 때 멤버 함수가 요청에 대한 처리 모듈일 경우
객체에 대한 참조 값이 함께 필요한 이유는 멤버 함수는 반드시 객체가 있 어야 실행 가능하기 때문
- Functor 클래스를 정의하는 데 template 기법을 사용하는 이유는
Functor 클래스 내부의 함수 또는 멤버 함수 포인터가 가리키는 실제 함수가
인자를 가진다든지 되돌리는 자료가 있을 경우 이들에 대한 자료형을 표현하기 위해서임
- 아무리 template 기법을 적용하더라도 형식 인자의 개수는 구체적으로 지정되어야 하기 때문에
Functor 클래스는 내부의 함수 포인터가 가리키는 실제 함수가 몇 개의 인자를 가지는지,
또 되돌리는 자료형이 존재하는지에 따라 각각 다른 클래스로 정의
* Command 패턴 정리
- Command 패턴은 요청을 처리할 작업을 일반화시켜 요청의 종류와는 무관하게 프로그램 작성이 가능하게 만들어 주는 것
- Invoker는 실제 Command 클래스의 Execute() 멤버 함수를 호출해주는 것으로 별도의 클래스로 정의될 수도 있고 클라이언트도 될 수 있음
* 유용한 경우
- 그래픽 사용자 인터페이스(GUI) 등을 구현 시 메뉴나 버튼에 수행할 작업을 일반화 시켜 설정하고자 할 때 유용
- 경우에 따라서는 동일한 메뉴에 대해서 동적으로 다른 Command 클래스 객체를 설정함으로써 동일한 메뉴나 버튼이 선택되더라도 상황에 따라 다른 작업을 수행
- 작업 수행을 요청한 시점과 실제 작업을 수행하는 시점을 달리 하고 싶을 때에도 유용
* 결론
- Command 패턴은 외부로부터 요청이 전달될 때
이를 받아주는 프로그램 모듈은 미리 작성해 두고,
각각의 요청에 대해 요청 처리를 수행하는 모듈은 개별 응용 프로그램마다
플러그인 시키는 콜백(Callback) 형태의 프로그램 작성에 매우 유용
- 따라서 여러분이 충분한 이해와 함께 많이 활용할 수 있기를 기대
솔루션 탐색기에서 .cpp 파일을 지웠지만
실제 vcxproj 파일에서는 삭제되지 않은 경우이다
이 경우에는 vcxproj 파일을 메모장을 읽어들여서 열어서
해당 .cpp 파일이 들어있는 xml 부분을 삭제해주면 된다
오른손 좌표계 사용
+z : 화면 밖으로 나오는 방향
모든 각은 radian으로 표시
객체는 자신의 로컬 좌표 공간에서 묘사(object coordinate space)
신 그래프에서 모든 변환이 객체에 적용된 후에 월드 좌표 공간으로 변환
월드 좌표 공간에서 카메라와 빛(light)을 포함
- 요구사항 결정
- 인수 테스트 생성
- 우선 순위 설정
개발자 팀은 요구사항을 구현
구현이 인수 테스트를 통과하는지 확인
테스팅 팀은 구현이 원래 어떻게 동작해야 하는지,
어떻게 동작하면 안되는지 검사
테스터는 고객팀을 도와 인수 테스트를 개발하고 개발팀은 테스트를 통과