[DirectX] COM(Component Object Model)

 COM은 DirectX의 프로그래밍 언어 독립성과 하위 호환성을 가능하게 하는 기술. COM 객체를 흔히 인터페이스라 부른다. C++클래스로 간주하고 사용. 그 세부사항은 프로그래머에게 드러나지 않는다.  프로그래머가 알아야 할 것은 COM 인터페이스로의 포인터를 특별한 함수들을 통해 얻거나, 다른 COM 인터페이스 메서드를 이용해서 얻는 방법 뿐이다.  COM인터페이스에는 new나 delete 키워드를 사용하지 않는다.  인터페이스를 다 사용하고 난 후에는 Release 메서드를 호출해줘야 한다. 각 COM 객체들이 자신만의 고유한 방식으로 메모리를 관리하기 때문.

디자인 패턴 - 객체 풀(Object pool)

객체를 매번 할당, 해제하지 않고 고정 크기 풀에 들어 있는 객체를 재사용함으로써 메모리 사용 성능을 개선한다. 메모리 단편화를 방지한다. 게임이 실행될 때 메모리를 미리 크게 잡아놓고 쓴다. 재사용 가능한 객체들을 모아놓은 객체 풀 클래스를 정의한다. 여기에 들어가는 객체는 현재 자신이 '사용 중'인지 여부 를 알 수 있는 방법을 제공해야 한다. 초기화될 때 사용할 객체들을 미리 생성하고(보통 같은 종류의 객체를 연속된 배열에 넣는다), 이들 객체를 '사용 안 함' 상태로 초기화한다. 새로운 객체가 필요하면 풀에 요청한다. 풀은 사용 가능한 객체를 찾아 '사용 중'으로 초기화한 뒤 반환한다. 객체를 더 이상 사용하지 않는다면 '사용 안 함' 상태로 되돌린다. 이런 식으로 메모리나 다른 자원 할당을 신경쓰지 않고 마음껏 객체를 생성, 삭제할 수 있다. 언제 쓰는가? 객체를 빈번하게 생성/삭제 객체들의 크기가 비슷 객체를 힙에 생성하기가 느리거나, 메모리 단편화가 우려됨 데이터베이스 연결, 네트워크 연결처럼 접근 비용이 비싸면서 재사용 가능한 자원을 객체가 캡슐화할 때 주의사항 메모리 낭비 가능성 사용 가능 객체 개수가 정해져 있다. 객체를 위한 메모리 크기가 고정되어 있다. (가장 큰 자료형에 맞춰야 함) 즉, 객체 크기 별로 풀을 나누는 게 좋다. 초기화에 주의 GC와의 충돌에 주의 사용 가능한 객체를 찾기 위해 빈칸 리스트(Free list) 를 고려해볼 수 있다. 객체가 풀과 커플링되는가?  풀을 통해서만 객체를 생성하고자 하면 그렇게 하라. 사용 중인지 여부를 객체 내부에서 알아낼 수 있다. 그렇지 않다면?  어떤 객체라도 풀에 넣을 수 있지만, 사용 중인지의 상태를 객체 외부에서 관리해야 한다. 객체 초기화 시 주의점은?  객체를 풀 안에서 초기화한다면, 객체를 완전히 캡슐화 가능하다. 풀 클래스가 객체 초기화 때문...

디자인 패턴 - 더티 플래그(Dirty flag)

계속해서 변경되는 ' 기본값 '이 있다. 또한 ' 파생값 '은 기본 값에 비싼 작업을 거쳐야 얻을 수 있다. 더티 플래그는 파생 값이 참조하는 기본 값의 변경 여부를 추적한다. 즉 더티 플래그는 기본값이 변경되면 켜진다 . 파생값을 써야 할 때, 더티 플래그가 켜져 있다면 다시 계산한 뒤에 플래그를 끈다 . 만약 플래그가 꺼져 있다면 이전에 캐시해놓은 파생 값을 그대로 사용 한다. 어떤 값이 더 이상 맞지 않다는 뜻으로 '더티'하다고 칭한다. 플래그란 둘 중 하나의 상태만 될 수 있는 작은 데이터를 뜻한다. 깨끗하지 않은 상태를 플래그로만 표시하고 그때그때 계산하지 않고 최종적으로 더티 플래그로 표시된 값들만 계산함으로써 중복된 계산을 피할 수 있다. 주로 계산과 동기화 작업에 사용할 수 있다. 사용 조건 파생 값이 사용되는 횟수보다 기본 값이 더 자주 변경되어야 한다. 점진적으로 업데이트하기가 어려워야 한다. 주의. 상당한 시간이 걸리는 작업을 지연해놨다가 결과를 보고 싶어 할 때 처리를 시작한다면, 짜증나는 랙이 생길 수 있다.

디자인 패턴 - 서비스 중개자 패턴(Service locator pattern)

서비스를 구현한 구체 클래스는 숨긴 채로 어디에서나 서비스에 접근할 수 있게 한다.  객체나 시스템 중에 거의 모든 코드에서 사용되는 것들이 있다. 이런 시스템은 게임 전체에서 사용 가능해야 하는, 일종의 서비스 라고 볼 수 있다.(메모리 할당, 로그, 난수 생성 등) 서비스를 사용하는 코드로부터 서비스가 누구인지 (서비스를 구현한 구체 클래스 자료형이 무엇인지), 어디에 있는지 (클래스 인스턴스를 어떻게 얻을지)를 몰라도 되게 해준다. 서비스는 여러 기능을 추상 인터페이스로 제공한다. 구체 서비스 제공자 (Service provider)는 이런 서비스 인터페이스를 상속받아 구현 한다.  이와 별도인 서비스 중개자 (Service locator)는 서비스 제공자의 실제 자료형과 이를 등록하는 과정은 숨긴 채 적절한 서비스 제공자를 찾아 서비스에 대한 접근을 제공 한다. 서비스 중개자는 서비스 제공자를 등록하고, 서비스를 사용하는 측에서 이 서비스를 이용할 수 있도록 중개해준다. 서비스 등록은?  외부 코드에서 등록할 수도 있고, 컴파일 시 바인딩될 수도 있다. 런타임에 설정 값을 읽을 수도 있다. 서비스를 못 찾으면?  사용자가 알아서 처리. 혹은 단언문으로 게임을 멈춤. 널 서비스 반환. 서비스 범위는?  전역(언제 어디에서 사용되는지 제어 불가)  특정 클래스로 제한(커플링 제어 가능. 중복 가능성) 사용처 :  접근해야 할 객체가 있다면 전역 메커니즘 대신  필요한 객체를 인수로 넘겨줄 수 없는지 부터 봐야 한다. 쉽고 커플링을 명확히 보여줄 수 있다.  렌더링 함수 매개변수에 렌더링에 관련된 것만 있어야지 로그 같은 게 섞여 있으면 곤란하다.  어떤 시스템은 본질적으로 하나뿐이다. 대부분의 게임 플랫폼에 오디오나 디스플레이 시스템이 딱 하나만 있다.  서비스 중개자는 일종의 더 유연하고 더 설정하기 좋은 싱...

디자인 패턴 - 타입 객체 패턴(Type object pattern)

의도 :  클래스 하나를 인스턴스별로 다른 객체형으로 표현할 수 있게 만들어, 새로운 '클래스들'을 유연하게 만들 수 있게 한다.  데이터는 게임 코드를 빌드하지 않고도 변경할 수 있어야 한다. 더 나아가 새로운 데이터를 만들고 수정하는 데에 프로그래머의 도움이 필요 없도록 한다.  예를 들어 수백 종의 몬스터를 전형적인 OOP 개념을 만들어내면, 몬스터의 하위 클래스가 너무나도 많아진다.  몬스터를 상속받는 하위 몬스터들을 계속 만들어내지 말고, 몬스터 공통의 동작인 몬스터 클래스와 종족을 나타내는 클래스를 따로 만들어서 구성하자.  이렇게 되면 종족 클래스는 몬스터의 '타입'을 정의한다. 각각의 종족 객체는 개념적으로 다른 '타입'을 의미한다.  그리고 설정 파일에서 읽은 데이터로 종족 인스턴스를 만들어낸다. 그러면 코드 상에서 클래스 상속으로 만들던 타입 시스템의 일부를 런타임에 정의할 수 있는 데이터로 옮긴 셈이다.  타입 객체(Type object)와 타입 사용 객체(Typed object) 클래스를 정의한다.  모든 Type object는 논리적으로 다른 타입을 의미 한다.   Typed object는 자신의 타입을 나타내는 Type object를 참조 한다.  타입 사용 객체는 타입 객체를 생성자에서 레퍼런스로 받고, 이 레퍼런스에서 초기값을 받거나 동작을 포워딩한다. 사용 : 나중에 어떤 타입이 필요할지 알 수 없거나(새로운 몬스터가 추가되는 등), 컴파일이나 코드 변경 없이 새로운 타입을 추가하거나 변경하고 싶을 때 사용한다. 주의 :  타입 객체를 직접 관리해야 함.  타입 별로 동작을 표현하기 어려움. 타입 종속적인 데이터 를 정의하기는 쉬우나, 타입 종속적인 동작 을 정의하기가 어렵다. 이를 위해서, 동작을 각각 구현한 함수를 정의하고 타입 객체가 적당한 함수 포인터를 저장하게끔 할 수 있다(마치...

디자인 패턴 - 바이트코드 패턴(Bytecode pattern)

게임에서의 마법 하나하나를 만들거나 고칠 때마다 코드를 수정하고 컴파일과 빌드를 거치기에는 반복이 너무 비효율적이다. 이럴 때, 코드를 수정하는 대신 코드는 특정 데이터를 읽게 하고, 데이터를 만들어서 반복을 수행하면 훨씬 효율적일 것이다. 행동을 데이터 파일에 따로 정의해놓고 게임 코드에서 읽어서 실행할 수 있다면 많은 장점이 있다. 데이터를 정의하기 위해 어떻게 할 것인가? 인터프리터 패턴 을 통해 데이터를 만들 수도 있겠다. 그러나, 인터프리터 패턴은 너무나도 느리고 메모리를 많이 소비한다. 더 빠른 수단을 찾아보자. 극단적으로 생각해보면, 기계어가 가장 빠를 것이다. 기계어의 장점. 밀도가 높으며, 선형적이고, 저수준이며, 그러므로 빠르다. 그러나 데이터를 기계어로 짜게하는 것은 어불성설이다. 대신 가상 기계어를 정의하면 어떨까? 그리고 그 가상 기계어를 실행하는 간단한 에뮬레이터도 만든다면? 이 가상 기계어는 게임에서 완전히 제어할 수 있으며, 밀도가 높고 선형적이고 상대적으로 저수준이다. 이 에뮬레이터를 가상 머신 이라 하고, 가상 기계어를 바이트 코드 라 하자. 바이트코드 패턴을 사용하면 좋은 경우 언어가 너무 저수준이라 만드는 데 손이 많이 가거나 오류가 생기기 쉽거나 컴파일 시간이나 다른 빌드 환경 때문에 반복 개발하기가 너무 오래 걸리거나 정의하려는 행동을 나머지 코드로부터 격리하고자 할 때 네이티브 코드보다는 느리므로 성능이 민감한 곳에 사용하지는 말자. 만드려는게 일종의 API라고 생각하면 좀 더 접근하기 쉬울 것이다. 마법 데이터를 만드는 예제를 통해 알아보겠다. 마법은 명령어 집합으로 생각한다. 그리고 그 명령어는 열거형 값을 배열에 저장해 데이터로 인코딩한다. 한 바이트로 전체 열거형 값을 다 표현할 수 있다. 데이터를 구성하는 코드가 실제로는 이런 바이트들의 목록이다보니 바이트코드라 부른다. 명령 하나를 실행하려면 어떤 명령인지 보고 이에 맞는 API메서드...

디자인 패턴 - 인터프리터 패턴(Interpreter pattern)

문자열을 읽어서 이를 문법 구조로 표현하는 객체 집합인 추상 구문 트리로 만든다. 이런 추상 구문 트리를 만드는 데에서 끝나지 않고 이를 실행한다. 표현식 혹은 하위표현식 객체로 트리를 만들고, 진짜 객체지향 방식으로 표현식이 자신을 평가하게 한다. 문법규칙을 클래스로 표현한 구조 도메인 특화 언어를 사용하기 위한 디자인 패턴 특화 언어는 범용 언어보다 고속으로 처리될 수 있다. 보통 각각의 심볼에 대한 클래스를 가진다. 특화 언어의 예: SQL, 통신프로토콜 언어 등 단점  코드를 로딩하면서 작은 객체를 많이 만들고 연결 객체와 객체를 잇는 포인터가 많은 메모리를 소모 포인터를 따라 하위표현식에 접근해야 하기 때문에 데이터 캐시에 치명적. 동시에 가상 메서드를 호출하는 것은 명령어 캐시에 치명적. 결론적으로, 느리다.

인공지능 - 유한 상태 기계(Finite state machine)

FSM은 기초적이지만, 아주 유용하게 쓰일 수 있다. 점점 행동 트리(Behavior tree)나 계획 시스템(Planning system)을 많이 쓰는 추세지만, 다음과 같은 특정 문제 해결을 위한 모델링으로써는 충분하다. 내부 상태에 따라 객체 동작이 바뀔 때 이런 상태가 그다지 많지 않은 선택지로 분명하게 구분될 수 있을 때 객체가 입력이나 이벤트에 따라 반응할 때 게임 AI로도 이용되지만, 입력 처리, 메뉴 화면 전환, 문자 해석, 네트워크 프로토콜, 비동기 동작 등을 구현하는 데에도 많이 사용된다. 유한 상태 기계(Finite state machine) 가질 수 있는 '상태'가 한정된다. 한 번에 '한 가지' 상태만 될 수 있다. '입력'이나 '이벤트'가 기계에 전달된다. 각 상태에는 입력에 따라 다음 상태로 바뀌는 '전이'가 있다. 스테이트 패턴 은 유한상태기계를 구현하는 방법 중 하나이다. 순수하게 형식만 놓고 보면, '상태, 입력, 전이'가 FSM의 전부다. 상태 객체에 필드가 따로 없다면 정적 객체로 만들어 쓰면 된다. 상태 기계는 엄격하게 제한된 구조를 강제함으로써 복잡하게 얽히는 코드를 정리할 수 있게 해 준다. 그러나 FSM에는 미리 정해놓은 여러 상태와 현재 상태 하나, 하드코딩된 전이만 존재한다. 그러므로 유한상태기계를 인공지능같이 더 복잡한 곳에 적용하다보면 한계에 부딪히게 된다. 병행 상태 기계  여러 상태를 각각 참조해서 사용한다. 예를 들어 플레이어 캐릭터가 무엇을 하고 있는가, 플레이어 캐릭터가 무엇을 들고 있는가 등으로 나눠서 병행으로 들고 있는 것이다.  두 상태 기계가 서로 연관이 없다면 잘 맞는 방법이다. 그러나 서로 상호작용하기 시작하면 지저분해진다. 계층형 상태 기계 상태 기계를 객체지향 코드라고 생각하고, 상속으로 여러 상태가 코드를 공유하게끔...

디자인 패턴 - 경량 패턴(Flyweight pattern)

정의 : 공유를 통해 많은 수의 소립 객체들을 효과적으로 지원한다.  많은 인스턴스가 공유하는 정보는 하나의 클래스로 만들고, 인스턴스별로 달라야 하는 상태값만 저장하는 클래스를 만들어서 공유 정보 클래스를 참조한다.  하나의 공유 정보 클래스와 무수한 인스턴스를 생성하면 중복된 정보를 메모리에 올릴 필요가 없어진다. 예를 들어 풀을 그리는데 풀의 텍스쳐와 메시를 공유 정보에 두고, 높이와 넓이처럼 인스턴사마다 다른 상태값만 따로 저장하고 공유 정보는 참조로 구성한다. Direct3D, OpenGL 모두 이런 인스턴스 렌더링(Instance rendering)으로 지원한다. 모든 객체의 데이터 값이 같아서 공유할 수 있는 데이터인 '고유 상태(Intrinsic state)'와 인스턴스 별로 값이 다른 '외부 상태(extrinsic state)' 또한 예시로서 지형 타일을 예로 들 수 있는데, 지형 속성은 고유 상태로 두고 하나의 인스턴스를 참조하고, 타일의 위치는 외부 상태로 만들어서 배열을 형성할 수도 있다. 이렇게 하면 지형 타일을 만드는 World는 지형의 세부 정보와 커플링되지 않으며, 타일 속성은 지형 타일 객체에서 참조하는 고유 상태를 통해 알아낼 수 있다. 열거형을 통해 스위치문을 만들 것이라면 경량 패턴을 고려해볼 수 있다. 예시: class World {     private :         Terrain* tiles [ WIDTH ] [HEIGHT]; } void  World: : generateTerrain ( ) {     for ( int i=0;i<WIDTH;i++ ) {         for ( int j=0;j<HEIGHT;j++ ) {             tiles [ i ]...

디자인 패턴 - 프록시 패턴(Proxy pattern)

이미지
정의 : 어떤 객체에 대한 접근을 제어하기 위한 용도로 대리인이나 대변인에 해당하는 객체를 제공하는 패턴 프록시는 진짜 객체를 대신하는 역할을 맡는다. 클라이언트에서 실제 객체의 메소드를 호출하면 프록시가 그 호출을 중간에 가로챈다. 그리고 간접적으로 작업을 처리하게끔 만든다. 원격 프록시 :  원격 객체에 대한 접근을 제어. 네트워크 상 다른 객체 호출 등. 가상 프록시 :  생성하기 힘든 자원에 대한 접근을 제어. 객체 생성 도중 임시로 자기가 기능을 처리하다가 객체 생성이 완료된 뒤에는 진짜 객체에게 그냥 일을 넘겨준다.  예를 들어 로딩 시 객체를 생성하느라 프로그램이 아예 멈춰있지 않게끔 하는 용도로 쓰일 수 있다. 만약 이미지를 출력하는 객체가 있는데 이미지 로딩 시간이 오래 걸린다면, 그동안 그 자리에 임시 이미지를 띄운다든가. 보호 프록시 :  접근 권한이 필요한 자원에 대한 접근을 제어. 클라이언트 별로 호출할 수 있는 메소드를 제한한다거나. 방화벽, 스마트 레퍼런스, 캐싱, 동기화, 복잡도 숨김, 지연 복사(CopyOnWrite) 등.

디자인 패턴 - 스테이트 패턴(State pattern)

정의 : 객체의 내부 상태가 바뀜에 따라서 객체의 행동을 바꿀 수 있다. 마치 객체의 클래스가 바뀌는 것과 같은 결과를 얻을 수 있다.  스테이트 객체로 일련의 행동을 캡슐화하고 이를 컨텍스트 객체에서 상태에 따라 갈아낀다. 그러면 컨텍스트 객체는 자신의 상태에 따라 스테이트 객체의 행동을 하게 된다.  상태를 기반으로 하는 행동을 캡슐화하고, 행동을 현재 상태한테 위임한다. 상태 전환은 스테이트 클래스에서 제어할 수도 있고, 컨텍스트 클래스에서 제어할 수도 있다.  스트래티지 패턴과 같은 방식으로 행동을 상속해서 사용한다. 스테이트 패턴은 상황에 따라 컨텍스트(Context) 객체에서 여러 스테이트 객체 중 하나가 내부 상태를 나타내고, 이 스테이트 객체에 따라 컨텍스트 객체의 행동도 자연스럽게 바뀐다. 클라이언트는 상태 객체에 대해 몰라도 상관 없다.  이 점에서 스트래티지 패턴과의 차이가 있다. 스트래티지 패턴을 사용할 때에는 클라이언트에서 컨텍스트 객체에게 어떤 전략(Stratege) 객체를 사용할지를 지정해준다. 일반적으로 스트래티지 패턴은 서브클래스를 만드는 대신 행동을 상속하여 유연성을 극대화시키기 위해 쓰인다. 스트래티지 패턴을 사용하면 구성을 통해 행동을 정의하는 객체를 유연하게 바꿀 수 있다.  바꿔 쓸 수 있는 행동을 캡슐화한 다음, 실제 행동은 다른 객체에 위임한다. 스테이트 패턴은 상태 객체를 바꾸는 것만으로 컨텍스트 객체의 행동을 바꿀 수 있다. 애니메이션 상태 제어, 유닛의 상태변경(공격<->대기<->이동 등) 등에 쓰일 수 있다. 유한 상태 기계(FSM) 을 구현하는 좋은 방법이다. 예시: State { Handle ( ) } IdleState : State { Handle ( ) { IdleAnimation . Play } MoveState : State { Handle ( ) { MoveAnimation . Pl...

디자인 패턴 - 컴포지트 패턴(Composite pattern)

정의 : 객체들을 트리 구조로 구성하여 부분과 전체를 나타내는 계층구조로 만드는 것.  클라이언트에서 개별 객체와 다른 객체들로 구성된 복합 객체를 똑같은 방법으로 다룰 수 있다. 개별 객체와 다른 개별객체들을 포함하는 복합 객체를 구분할 필요 없이 똑같은 작업이 가능하다.  예를 들어 파일시스템의 트리 구조. GUI 시스템의 캔버스-패널-버튼-텍스트 등의 트리 구조.  부분-전체 관계를 가진 객체 컬렉션이 있으며, 이 객체들을 모두 똑같은 방식으로 다루고 싶을 때 사용한다.  Component 인터페이스는 자신의 구성요소로서의 역할을 수행하는 메소드인 Operation과, 자신의 하위에 다른 Component를 추가/삭제하거나 조회하는 메소드를 제공한다.  컴포넌트 인터페이스를 만들고, 이를 복합(Composite) 객체와 리프 객체에서 모두 구현한다. 각자 용도에 맞는 메소드만 구현하고, 그 외 쓸모없는 메소드는 기본 메소드를 그대로 쓸 수 있도록 한다. 컴포넌트는 각기 자신의 Operation을 구현한다. 추가로 자식 컴포넌트를 관리하는 메소드를 구현할 수도 있다.  리프 노드는 자식이 0개인 복합 객체로 볼 수 있으며 사실상 자식이 없기 때문에 굳이 자신의 하위 컴포넌트를 관리하는 메소드를 오버라이드해서 구현하지 않고 기본 메소드를 쓰는 것이라 볼 수 있다.  복합객체의 Operation 자신의 할 일 뿐 아니라 자신이 가지고 있는 개별객체들의 Operation을 재귀적으로 호출한다. 이로써 최상위 객체의 Operation를 실행한다면 트리 구조로 가지고 있는 모든 자식 객체들의 Operation이 계층적으로 실행된다.  컴포지트 패턴은 단일 역할 원칙을 깨는 대신 투명성을 확보한다. 클라이언트에서는, 컴포넌트 인터페이스를 구현하는 객체가 개별 리프 노드인지 최상위 복합 노드인지를 구분하지 않고 똑같은 방식으로 처리할 수 있다. 클라이언트를 단순화할 수 있는...

디자인 패턴 - 이터레이터 패턴(Iterator pattern)

정의 : 컬렉션 구현 방법을 노출시키지 않으면서도 그 집합체 안에 들어있는 모든 항목에 접근할 수 있게 해 주는 방법을 제공하는 패턴 객체의 컬렉션에 대한 반복작업을 처리하는 방법을 캡슐화. 이터레이터 인터페이스를 정의해두고, 콜렉션에서는 이 인터페이스를 구현. 클라이언트에서는 이터레이터를 이용해 어떤 컬렉션이든 같은 방식으로 사용 가능. HasNext ( ), MoveNext ( ) 이터레이터는 기본적으로 위의 두 메소드를 구현해둔다. 보통 이터레이터를 컬렉션으로부터 얻었을 때, 이터레이터는 첫 번째 항목이 아니라 그 이전을 가리키고 있다. 즉, MoveNext()를 최초 한 번 수행해서 얻는 값이 컬렉션의 첫번째 값. 예시: SomeCollection :  Itrerator Client . main ( ) { Iterator iter = SomeCollection . GetIterator ( ); iter . Next ( ); ]

디자인 패턴 - 템플릿 메소드 패턴(Template method pattern)

템플릿 메소드 패턴 정의 : 메소드에서 알고리즘의 골격을 정의한다. 알고리즘의 여러 단계 중 일부는 서브클래스에서 구현할 수 있다.   알고리즘의 각 단계들을 정의하며, 그 중 한 개 이상의 단계가 서브클래스에 의해 제공될 수 있다. 템플릿 메소드를 이용하면 알고리즘의 구조는 그대로 유지하면서 서브클래스에서 특정 단계를 재정의할 수 있다.  여러 단계 가운데 하나 이상이 추상 메소드로 정의되며, 그 추상 메소드는 서브클래스에서 구현된다. 서브클래스에서 일부분을 구현할 수 있도록 하면서도 알고리즘의 구조는 바꾸지 않아도 된다.  후크(Hook)를 구현할 수 있다. 추상 클래스에서 선언되는 메소드지만 기본적인 내용만, 혹은 아무 내용도 들어있지 않은 메소드다. 이를 이용하면 서브클래스 입장에서는 다양한 위치에서 알고리즘에 끼어들 수 있다.  알고리즘의 특정 부분이 선택적으로 적용되어야 하는 경우에 후크를 오버라이드해서 쓸 수 있다. 예시 : AbstractClass {      TemplateMethod ( ) { Primitive1 ( ); Primitive2 ( ); ConcreteOp ( ); if ( Hook ( ) ) something; } }    ConcreteClass : AbstractClass {     override Primitive1 ( ); override Primitive2 ( ); override Hook ( ); } Client . ConcreteClass . TemplateMethod ( );

디자인 패턴 - 퍼사드 패턴(Facade pattern)

퍼사드 패턴 정의 : 어떤 서브시스템의 일련의 인터페이스에 대한 통합된 인터페이스를 제공한다. 고수준 인터페이스를 정의한다. 클라이언트를 복잡한 서브시스템과 분리시켜주는 역할을 한다. 구성을 통해 퍼사드에서 서브시스템에 있는 모든 구성요소에 접근할 수 있게끔 한다. 퍼사드 클래스는 서브시스템 클래스들을 캡슐화하지 않는다. 그냥 서브시스템 클래스의 기능을 사용할 수 있는 간단한 인터페이스만 제공한다. 어댑터 패턴은  인터페이스를 변경 해서 클라이언트에서 필요로 하는 인터페이스로 적응시키기 위한 용도. 퍼사드 패턴은 어떤 서브시스템에 대한 간단한 인터페이스를 제공. 예시: SubSystemOne , SubSystemTwo, SubSystemThree AFacade{ DoSomething(){ SubSystemOne.Do1(); SubSystemTwo.Do2(); SubSystemThree.Do3(); } Client . AFacade . DoSomething ( ); // All subsystem of facade do their job.

디자인 패턴 - 어댑터 패턴(Adapter pattern)

어댑터 패턴 정의 : 한 클래스의 인터페이스를 클라이언트에서 사용하고자 하는 다른 인터페이스로 변환해주는 패턴. 호환되지 않는 인터페이스를 그대로 활용 가능. 클라이언트와 구현된 인터페이스 분리 가능. 클라이언트(Client), 어댑터(Adapter), 어댑티(Adaptee). 클라이언트에서 타겟 인터페이스를 사용하여 메소드를 호출함으로써 어댑터에 요청 어댑터에서는 어댑티 인터페이스를 사용하여 그 요청을 어댑티에 대한 메소드 호출로 변환 클라이언트에서는 호출 결과를 받긴 하지만 중간에 어댑터가 껴 있는지는 알 수 없음 예시: Target { Request ( ) } Adapter : Target { Request ( ) { Adaptee . SpecificRequest ( ) } } Client . Target . Request ( ) ; //Adaptee . SpecificRequest ( ) executed.

디자인 패턴 - 커맨드 패턴(Command pattern)

이미지
정의 : 요청을 객체 형태 캡슐화하는 것. 사용자가 보낸 요청을 나중에 이용할 수 있도록 메소드 이름, 매개변수 등 요청에 필요한 정보를 저장 또는 로깅, 취소할 수 있게 만든 패턴 명령 패턴은 메서드 호출을 실체화한 것이다. 명령 패턴은 콜백을 객체지향적으로 표현한 것. 요청을 하는 객체와 그 요청을 수행하는 객체를 분리 한다. 특정 객체에 대한 특정 작업 요청을 캡슐화 한다. 요청 내역을 큐에 저장하거나 로그로 기록할 수 있다. 실행된 작업을 저장해뒀다가 실행취소도 가능하다. 매개변수를 써서 여러 가지 다른 요구 사항을 집어넣을 수도 있다. 외부에서 볼 때 자신이 요청한 명령이 실제로 어떻게 처리되는지 알 수 없게 캡슐화. 그냥 execute 메소드만 호출하면 요구사항이 처리되도록 한다.  Command는 실제로 명령을 수행할 Receiver 객체를 가지고 있다. Command에서 Execute()만 구현해두면 요청하는 쪽에서는 상세를 알 필요가 없다. Execute() 내에서 Receiver 객체를 통해 작업을 수행한다.  Invoker는 Client로부터 전달받은 Command 객체를 통해 명령을 발동한다. Action에 따른 일련의 Command 객체들을 가지고 있을 수도 있다. 필요에 따라 명령 발동 기록을 남긴다.  Receiver는 Command의 Execute()에서 하달받은 명령을 실제로 수행한다.  Client는 어느 시점에 어떤 명령을 수행할지 결정한다. 명령을 수행하려면, Client 객체는 Invoker 객체로 Command 객체를 전달해야 한다. Command, Receiver, Invoker, Client Command 객체는 Receiver를 가지고 있고, Receiver의 메소드를 호출한다.(Execute(), Undo()) Receiver는 자신에게 정의된 메소드를 수행한다. Command 객체는 Invoker 객체에 전달되어 명령을 발동하게 ...

디자인 패턴 - 싱글턴 패턴(Singleton pattern)

정의 - 해당 클래스의 인스턴스가 하나만 만들어지고, 어디서든 그 인스턴스에 접근할 수 있도록 하기 위한 패턴.  객체를 하나만 만들어서 유일하게 관리하는 디자인 패턴. 생성자가 여러 차례 호출되더라도 실제로 생성되는 객체는 하나이고, 최초 생성 이후에 호출된 생성자는 최초의 생성자가 생성한 객체를 리턴한다. 기초적인 구현은 생성자를 private으로 만들고, 정적 메소드에서 인스턴스를 반환하는 것.   멀티스레딩 관련 문제에는 주의 할 것. 싱글턴을 상속할 수도 있다. 크로스플랫폼으로 무언가를 할 때, 플랫폼 종속적인 부분은 자식 클래스에 맡겨두고 부모 클래스에서는 전처리기 지시문 같은 걸로 플랫폼을 파악해서 싱글턴 객체를 만들면 된다. 전역 변수의 문제점 컴퓨터 과학에서 전역 상태에 접근하거나 수정하지 않는 함수를 '순수(pure)' 함수라고 한다. 순수 함수는 이해하기 쉽고 컴파일러가 쉽게 최적화할 수 있다. 커플링을 조장한다. 멀티스레딩에 알맞지 않다. 싱글턴은 모든 스레드가 보고 수정할 수 있는 메모리 영역이 생기는 셈인데, 교착상태, 경쟁상태 등의 동기화 버그가 생길 수 있다. 싱글턴은 클래스로 캡슐화된 전역변수이므로, 위 문제점이 모두 발생한다. 또한, 한 개의 인스턴스/전역 접근. 이 두 가지 중 하나만 필요할 때에도 둘 다 사용하게 된다. 게으른 초기화 시점을 제어하기가 쉽지 않다. 메모리 할당을 제어할 수 있으려면 적절한 초기화 시점을 찾아야 한다. 대안 전역 접근 없이 클래스 인스턴스만 한 개 만들게끔 보장한다.  이미 전역인 객체로부터 객체를 얻을 수 있다. Log, FileSystem, Audio, Player 등을 각각 싱글턴으로 만드는 대신 Game이라는 하나의 싱글턴 객체가 갖고있게 하자. (최소지식 원칙에는 위배된다) 서비스 중개자를 사용할 수도 있다.