글

디자인 패턴 - 경량 패턴(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.