1. 소개
디자인 패턴은 일반적인 소프트웨어 디자인 문제에 대한 재사용 가능한 솔루션입니다.
이 솔루션은 소프트웨어 아키텍처를 설명하고 문서화하는 방법과 더불어 개발자들이 소프트웨어 설계에 대해 소통할 수 있는 공통 용어를 제공 해 줍니다.
디자인 패턴에는 생성 패턴, 구조 패턴, 동작 패턴 등 여러 가지 유형들이 존재 합니다.
생성 패턴들(Creational patterns)은 상황에 따라서 적절한 방식으로 객체를 생성하려고 시도하는 객체 생성 메커니즘을 다루고 있습니다.
구조 패턴들(Structural patterns)은 객체 구성을 다루며, 객체들 간의 관계를 형성하고 좀 더 큰 구조를 형성합니다.
행동 패턴들(Behavioral patterns)은 객체 간의 통신, 객체 간에 진행되는 작업과 그들이 서로 동작하는 방식에 중점을 둡니다.
2. 생성 패턴들
2.1 싱글톤
Singleton 디자인 패턴은 클래스가 오직 하나의 인스턴스만 가진다는 것이 확실하고, 그 인스턴스에 대한 전역 액세스 지점을 제공하는 데 사용됩니다.
- Singleton 디자인 패턴을 사용하는 한 가지 이점은 클래스의 인스턴스가 하나만 존재한다 것입니다. 이는 데이터베이스 연결이나 네트워크 소켓과 같은 리소스를 관리하는 클래스에 유용할 수 있습니다.
- 또한 이 패턴은 인스턴스에 대한 전역 액세스 지점을 제공하므로 코드의 모든 부분에서 인스턴스를 더 쉽게 사용할 수 있습니다.
2.2 팩토리 패턴
생성 될 객체의 정확한 클래스를 명시 없이 객체를 생성 방법을 제공합니다. 특정 유형의 객체를 만드는 메서드를 가지고 있습니다.
이 메서드는 생성할 객체 유형(타입)을 인수로 사용하고 해당 유형에 대한 새로운 객체를 반환합니다.
그림 2: 팩토리 UML.
- Factory 디자인 패턴을 사용하는 한 가지 이점은 객체들의 생성을 단일 위치 내로 중앙 집중화할 수 있어 코드를 모듈화하고 유지 관리하기 쉽게 만들 수 있다는 점입니다.
- 이 패턴은 객체 생성 구현을 쉽게 변경할 수 있으므로 디자인을 보다 유연하고 확장 가능하게 만들 수 있습니다.
- 정확한 클래스를 지정하지 않고도 객체를 생성할 수 있으므로 코드를 보다 일반성과 재사용성을 확보 할 수 있습니다.
2.3 추상 팩토리
구체화 클래스를 지정하지 않고 관련 객체 또는 종속 객체의 패밀리를 만들기 위한 인터페이스를 제공합니다.
- 시스템은 제품이 생성, 구성 및 표현되는 방식과 독립적이어야 합니다.
- 시스템은 여러 제품군들 중 하나로 구성되어야 합니다.
- 관련 제품 객체의 제품군들은 함께 사용하도록 설계되어야 하며, 이 제약 조건을 적용해야 합니다.
- 특정 애플리케이션 또는 프레임워크와 호환되는 객체를 생성하기를 원하지만, 런타임까지는 객체의 구체화 클래스를 생성하고 싶지 않을 경우에 유용합니다.
2.4 빌더 패턴
단계별 접근방식으로 복잡한 객체를 생성할 수 있도록 해줍니다. 객체의 구성을 해당 표현과 분리하여 다양한 표현들을 만들 수 있도록 해줍니다.
그림 4: 빌더 UML.
- 객체 생성 알고리즘은 시스템에서 분리되어야 합니다.
- 생성 알고리즘의 여러 표현들이 요구 됩니다.
- 핵심 코드를 변경하지 않고 새로운 생성 기능의 추가를 필요로 합니다.
- 생성 프로세스에 대한 런타임 제어가 필요합니다.
2.5 프로토타입 패턴
처음부터 새 객체를 만드는 대신 기존 객체를 복사하여 새 객체를 만들 수 있도록 합니다.
그림 5: 프로토타입 UML.
- 복잡한 객체를 생성하거나 새로운 객체를 만드는 비용이 높을 때 유용합니다.
- 클래스는 생성해야 하는 클래스들이 무엇인지를 알 수 없을 것입니다.
- 서브클래스들는 어떤 객체들이 생성 되어야 하는 지 지정할 수 있습니다.
- 부모 클래스는 자신들의 하위 클래스 생성을 연기하려고 합니다.
3. 구조적 패턴 - Structural patterns
3.1 어댑터 패턴
인터페이스들 중 하나 사이에 어댑터 클래스를 래핑함으로써 두 개의 호환되지 않는 인터페이스가 함께 작동하도록 허용해 줍니다.
이 어댑터 클래스는 가져온 클래스의 인터페이스를 클라이언트가 기대하는 인터페이스로 변환합니다.
그림 6: Adapter UML.
- 어댑터는 데이터를 다양한 형식으로 변환할 수 있을 뿐만 아니라 서로 다른 인터페이스를 가진 객체가 협업하도록 도울 수 있습니다.
- 양방향으로 호출을 변환할 수 있도록 양방향 어댑터(two-way adapter)를 만들 수 있습니다.
3.2 브릿지 패턴
추상화와 구현을 분리할 수 있으므로 둘이 독립적으로 다양해 질 수 있습니다.
그림 7: 브리지 UML.
- 추상화 및 구현은 컴파일 타임에 바인딩되지 않아야 합니다.
- 추상화와 구현은 독립적으로 확장 가능해야 합니다.
- 추상화 구현의 변경 사항은 클라이언트에 영향을 주지 않아야 합니다.
- 구현 세부 정보는 클라이언트에서 숨겨야 합니다.
3.3 컴포짓 패턴
객체를 단일 단위로 취급할 수 있도록 합니다. 객체를 트리 구조로 구성하고 간단한 객체에서 복잡한 객체를 만드는 데 사용됩니다.
그림 8: Composite UML.
- 객체의 계층적 표현을 필요로 합니다.
- 객체들과 객체들의 구성은 균등하게 취급되어야 합니다.
3.4 데코레이터 패턴
객체의 구조를 변경하지 않고 기존 객체에 새로운 동작을 동적으로 추가할 수 있도록 해줍니다.
그림 9: 데코레이터 UML.
- 클래스에 새 기능을 추가하거나 기존 클래스를 추가 기능으로 래핑하는 데 사용할 수 있습니다.
3.5 파사드 패턴
복잡한 시스템에 단순화된 인터페이스를 제공합니다.
그림 10: 파사드 UML.
- 시스템에 상호 연결된 클래스가 많거나 클라이언트가 제한된 수의 시스템 기능에만 액세스해야 하는 경우에 유용합니다.
- 복잡한 하위 시스템에서 클라이언트를 분리하고 시스템을 더 쉽게 유지 관리하고 수정할 수 있습니다.
3.6 플라이웨이트 패턴
객체 간에 공통 데이터를 공유하여 메모리 사용을 최소화하는 것을 목표로 합니다.
이는 각각의 객체가 별도의 데이터 인스턴스를 갖는 대신 여러 객체에서 사용할 수 있는 공유 객체를 생성하도록 만드는 것입니다.
그림 11: 플라이웨이트 UML.
- 애플리케이션의 메모리 공간을 줄이고 성능을 향상시킬 수 있습니다.
- 메모리 절약의 이점과 패턴 구현의 추가 복잡성 간의 균형을 신중하게 고려해야만 합니다.
3.7 프록시 패턴
클라이언트와 실제 주체 사이에 중간 객체를 제공합니다.
프록시 패턴은 다음과 같이 사용 할 수 있습니다:
그림 12: 프록시 UML.
- 잠재적으로 비용이 많이 들거나 리소스를 많이 사용하는 객체에 대한 자리 표시자(placeholder)를 제공합니다.
- 프록시는 미리 생성하는 대신 필요할 때만 실제 객체의 생성을 위해서 사용할 수 있습니다.
- 실제 주제에 대한 액세스를 제어합니다.
- 프록시를 사용하여 액세스 제한을 시행하거나 인증 및 권한 부여 확인을 구현할 수 있습니다.
- 실제 주제에 추가 기능을 추가합니다.
- 프록시를 사용하여 실제 주체에 대한 요청을 가로채고 요청을 전달하기 전이나 후에 추가 작업을 수행할 수 있습니다.
4. 행동 패턴들 - Behavioral patterns
4.1 Chain of Responsibility
객체가 요청을 처리하기 위해 객체 체인에 요청을 보낼 수 있도록 합니다.
Fig. 13: Chain of Responsibility UML.
- 여러 객체가 요청을 처리할 수 있고 요청을 처리해야 하는 특정 객체를 미리 알 수 없는 상황에 유용합니다.
- 전체 기능을 방해하지 않고 체인에서 객체를 쉽게 추가하거나 제거할 수 있습니다.
4.2 Command 패턴
요청을 객체로 캡슐화할 수 있으므로 수신자에게 전달되어 실행될 수 있도록 해줍니다.
Fig. 14: Command UML.
- 요청의 발신자와 수신자를 분리할 수 있습니다.
- 요청을 대기열에 넣거나 기록하고 실행 취소/다시 실행 기능을 지원하는 기능.
4.3 Iterator 패턴
클라이언트가 객체의 기본 표현을 노출하지 않고 집계 객체의 요소에 순차적으로 액세스할 수 있습니다.
Fig. 15: Iterator UML.
- 컬렉션의 특정 구현에 관계없이 클라이언트가 일관되고 균일한 방식으로 객체 컬렉션을 탐색할 수 있습니다.
4.4 Mediator 패턴
여러 객체가 구현 세부 정보를 몰라도 서로 통신할 수 있도록 해줍니다.
Fig. 16: Mediator UML.
- 이 패턴은 mediator로 알려진 통신의 중심점을 제공하며 객체 간의 중개자 역할을 제공합니다.
- 통신 로직을 객체 자체에서 분리하여 시스템의 복잡성을 줄여주기 때문에 서로 통신해야 하는 객체가 많은 경우에 유용합니다.
4.5 관찰자 패턴 - Observer
상태가 변경될 때 객체(주체)가 일련의 객체(관찰자)에게 알릴 수 있도록 합니다. 관찰자 패턴은 게시-구독 패턴이라고도 합니다.
그림 17: 관찰자 UML.
- 다양한 객체가 서로 동기화되도록 하고 싶을 때나 주제와 관찰자를 서로 독립적으로 재사용할 수 있기를 원할 때 유용합니다.
4.6 전략 패턴 - Strategy
다른 전략 객체로 전환하여 객체가 런타임 시 동작 또는 전략을 변경할 수 있도록 합니다.
Fig. 18: Strategy UML.
- 많은 관련 클래스들 간의 유일한 차이점은 그것들의 행동입니다.
- 알고리즘의 여러 버전 또는 변형이 요구됩니다.
- 알고리즘은 호출 코드가 노출되어서는 안 되는 데이터에 액세스하거나 활용합니다.
- 클래스의 동작은 런타임에 정의되어야 합니다.
- 조건문은 복잡하고 유지하기 어렵습니다.
4.7 템플릿 메서드 패턴
알고리즘의 단계를 정의하고 하위 클래스가 특정 단계를 무시할 수 있도록 허용하면서 알고리즘의 전체 구조를 계속 유지 할 수 있도록 해줍니다.
그림 19: 템플릿 메서드 UML.
- 알고리즘의 단일 추상 구현이 필요로 합니다.
- 하위 클래스 간의 공통 동작은 공통 클래스로 지역화되어야 합니다.
- 부모 클래스는 하위 클래스에서 동작을 균등하게 호출할 수 있어야 합니다.
- 대부분 또는 모든 하위 클래스는 해당 동작을 구현해야 합니다.
이상.
'프로그래밍' 카테고리의 다른 글
Getter, Setter와 리플렉션 (0) | 2024.02.02 |
---|---|
윈도우 용 Gnuplot 빌드해보기 (0) | 2024.02.01 |
[자바] 사용자의 터치로 완벽한 원 그리기 (0) | 2023.04.20 |
MinGW 정적 동적 라이브러리 (0) | 2023.04.19 |
네이티브 이미지의 동적 프록시 (0) | 2023.04.18 |