4월, 2017의 게시물 표시

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

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

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

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

디자인 패턴 - 이터레이터 패턴(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 객체에 전달되어 명령을 발동하게 된다. Invoker 객체는 필요

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

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

디자인 패턴 - 팩토리 패턴(Factory pattern)

팩토리 메소드 패턴 정의 - 객체를 생성하기 위한 인터페이스를 정의하는데, 어떤 클래스의 인스턴스를 만들지는 서브클래스에서 결정하는 패턴.   클래스 인스턴스를 만드는 일을 서브클래스에게 맡기는 것. 객체를 생성하는 작업을 자식 클래스에서 캡슐화한다.  Creator는 추상 클래스로서 객체를 생성하기 위해 구현할 팩토리 메소드를 정의한다. 이를 구현한 자식 클래스에서 어느 클래스의 인스턴스를 만들지 결정한다. 객체 생성과 사용 부분을 분리할 수 있다. 좀 더 느슨한 결합이 가능.  Creator는 실제 생성될 객체에 대한 사전지식이 아무것도 없다. 오로지 사용하는 서브클래스에 의해 객체 인스턴스가 결정된다.  간단한 팩토리와의 차이점. 간단한 팩토리는 단순히 객체 생성을 캡슐화했을 뿐이며, 팩토리 메소드 패턴은 객체 생성을 위한 프레임워크를 만들었기 때문에 어느 클래스의 인스턴스를 만들지에 대해 동적으로 결정할 수 있다.  팩토리 메소드 패턴은 구상 클래스에 대한 의존성을 줄이는 객체지향 디자인 원칙을 따른다. Dependency Inversion Principle.' 추상화된 것에 의존하도록 만들어라. 구상 클래스에 의존하지 않게끔 만들어라.' 고수준(추상화된) 구성요소가 저수준(구체화된) 구성요소에 의존하면 안 된다. 예시: SomeFactoryMethod : FactoryMethod ClassInstance instance = new SomeFactoryMethod . Create ( ); 추상 팩토리 패턴 정의 - 인터페이스를 이용하여 서로 연관된, 또는 의존하는 객체를 구상 클래스를 지정하지 않고 생성. 객체 구성을 통해 다른 객체의 레퍼런스를 이용해 인스턴스를 만든다. 예시 : SomeAbstractFactory : AbstractFactory AbstractFactory   aSomeFactory = new SomeAbstractFactory ClassInstance

디자인 패턴 - 데코레이터 패턴(Design pattern - Decorator pattern)

정의 - 주어진 상황 및 용도에 따라 객체에 추가적인 책임을 덧붙이는 패턴. 서브클래스를 통해 기능을 유연하게 확장하는 방법을 제공한다.  상속을 통해 구성요소의 형식을 맞춰서 감싸 사용하는 일종의 래퍼(Wrapper).  기존의 컴포넌트에 원래 있던 메소드를 호출하기 전, 또는 후에 데코레이터에서 별도의 작업을 처리하는 방식으로 기능을 추가한다.  데코레이터의 형식은 그 데코레이터로 감싸는 객체의 형식과 같다. 상속을 이용해서 형식을 맞추는 것. 인스턴스로 본래 컴포넌트를 가지고 있고, 또 그 자신도 컴포넌트와 같은 형식이므로 다른 데코레이터로 감쌀 수도 있다. Component, Decorator : Component ConcreteComponent : Component를 객체로써 사용. 이를 ConcreteDecorator : Decorator로 장식 가능. ConcreteDecorator는 Component 형식이므로 또 다른 Decorator로 장식 가능. 예시 : Component c = new OtherDecorator ( new SomeDecorator ( new ConcreteComponent)); c. Do ( ); //ConcreteComponent.Do() -> SomeDecorator.Do() -> OtherDecorator.Do() 순서로 호출.  기존 컴포넌트의 메소드가 A를 출력한다고 했을 때, 데코레이터로 감싸서 기존 컴포넌트의 함수를 호출한 뒤, B를 출력하게끔 한다. 그러면 컴포넌트 형식으로 해당 객체를 불러서 메소드를 실행 했을 때에, AB가 출력될 것이다. 계속 덧붙여서 ABCDEF 이런 식으로 행동을 추가할 수도 있다. 형식은 어디까지나 기존 컴포넌트 형식이다.  자바의 I/O가 데코레이터 패턴으로 구현되어 있다. FileInputStream으로 파일을 하나씩 읽고, BufferedInputStream으로 FileInputStream에서 읽은 내용을 버퍼링하는 식이다.

디자인 패턴 - 옵저버 패턴(Design pattern - Observer pattern)

이미지
정의 :  객체의 상태 변화를 관찰하는 관찰자들(Observer)의 목록을 객체에 등록하여, 상태 변화(Update)가 있을 때마다 객체가 옵저버들에게 통지(Notify)하는 디자인패턴  주체(Subject)가 자신의 상태변화를 관찰자들에게 통지하는 것이 핵심. 관찰자는 등록만 해 두면 다시 주체에게 접근할 필요 없이 통지(Notify)를 위한 인터페이스만 구현해두면 된다. 주체는 등록과 해지만 구현해두고 다른 관찰자가 붙든 떨어지든 자기 변화를 통지해주면 된다.  Subject 인터페이스 - NotifyObservers, RegisterObserver, UnregisterObserver  Observer 인터페이스 - Notify

디자인 패턴 - 스트래티지 패턴(Design pattern - Stratege pattern)

정의 : 알고리즘을 사용하는 클라이언트와 독립적으로 알고리즘군을 정의하고 각각을 캡슐화하는 것.  객체와 그 객체의 행동을 따로 분리해서 생각해보자. 각 객체는 자신의 행동을 직접 정의하고 있는 게 아니라 행동에 해당하는 다른 객체를 구성(인스턴스 변수로 다른 객체를 저장하는 방식)으로서 가지고 있다.  예를 들어 Behavior라는 인터페이스가 있다고 하자. 이 Behavior를 상속받아 정의한 클래스가 있다면 주체가 되는 객체는 자신의 행동을 직접 정의할 필요 없이 Behavior 인터페이스만 가지고 행동할 수 있으며, 동적으로 객체의 행동을 정하거나 교체할 수도 있다. 예시 :  Bird 클래스를 상속받는 Sparow, Crow, Penguin을 만들어보자. Sparow.Fly(), Crow.Fly(), Penguin.Fly()를 따로 구현하게 된다면 코드 중복이 발생하며, 확장이나 변경 등에도 유연하지 않다.  이를 방지하기 위해 FlyBehavior 인터페이스를 만들고, 이를 구현한 FlyByWings, FlyByNoWing을 만든다.  Bird는 Fly() 대신 this.FlyBehavior.Fly()를 호출하도록 한다. 스트래티지 패턴은 즉, 객체의 행동 중 바뀌어야 하는 것들을 분리한 인터페이스를 구성으로서 가지고 있게 한 것 이다.