목차
- ☆ 표시가 붙은 부분은 스터디 중 나온 얘기 혹은 제 개인적인 생각이나 제가 이해한대로 적어놓은 것으로, 책에 나오지 않는 내용입니다. 따라서 책에서 말하고자 하는 바와 다를 수 있습니다.
- 모든 이미지의 출처는 디자인패턴의 아름다움(왕정 저) 책 입니다.
CHAPTER 06. 생성 디자인 패턴
- 생성 디자인 패턴은 주로 객체 생성 문제를 해결하고 복잡한 생성 프로세스를 캡슐화하며 객체의 생성 코드와 사용 코드를 분리한다.
- 싱글턴 패턴 : 전역적으로 유일한 객체를 생성하는 데 사용
- 팩터리 패턴 : 같은 상위 클래스나 인터페이스를 상속하는 하위 클래스와 같이 비록 유형은 다르지만 서로 관련되어 있는 객체를 주어진 객체 타입에 맞게 생성하는 데 사용
- 빌더 패턴 : 복잡한 객체를 생성하는 데 사용되는데, 서로 다른 선택적 매개변수를 설정하여 다양한 객체를 사용자 정의할 수 있다.
- 프로토타입 패턴 : 기존 객체를 복사하는 방법을 사용하여 생성 비용이 높은 객체를 생성하는 시간을 절약한다.
6.1 싱글턴 패턴 (1)
- 어떤 클래스의 객체 또는 인스턴스를 단 하나만 생성할 수 있다면, 해당 클래스는 싱글턴 클래스이며, 이 디자인 패턴을 싱글턴 패턴이라고 한다.
- 싱글턴 패턴의 구현 : ☆ 이 책에 나온 내용과 비슷한걸 정리해둔게 있다. '자바 싱글톤 패턴의 변화 (다양한 싱글톤 패턴 구현 방법)'
- 싱글턴 패턴의 단점
- 클래스 간의 의존성을 감춘다. : ☆ 특히 스프링의 경우 어차피 component들은 기본적으로 싱글턴으로 동작한다. 따라서 개인적으론 의존성 감춘걸 풀기 위해 라이브러리에서 싱글턴을 쓴 경우 component로 한번 래핑해서 사용하는걸 선호한다.
- 테스트 용이성에 영향을 미친다.
- 매개변수가 있는 생성자를 지원하지 않는다. (☆ 사용못한다기 보다는, 매개변수가 의미 없다.)
- 싱글턴 패턴의 대안
- 정적 메서드
- 의존성 주입
6.3 팩터리 패턴 (1)
- 객체 생성과 사용이 섞여있는 경우, 클래스의 단일 책임을 명확히 하기 위해 별도의 클래스에 생성을 분리해 객체 생성만 담당하도록 할 수 있다. 이렇게 생성되는 클래스가 단순 팩터리 패턴이 적용된 팩터리 클래스이다. (== 정적 팩터리 메소드, 정적 팩터리 패턴)
- 생성을 위한 코드를 가끔씩만 수정한다면 개방 폐쇄 원칙을 완전히 만족하지 않아도 괜찮다.
- if 분기가 매우 많은 것이 아니라면 if 분기가 있어도 무방하다. (☆ 너무 SOLID 이런거 생각하지 말고, 트레이드 오프이니 적당하다면 그냥 그대로 해도 된다는 얘기이다.)
- 이 때, 분기 판단 논리 대신 다형성을 사용한 팩터리 메서드 패턴으로 변경하여 if 분기 판단 논리를 제거할 수 있다. (☆ 근데 어차피 생성을 위해 switch나 if 등의 코드가 들어가게 된다. 이 경우 사용하는 쪽은 OCP를 지킬 수 있어도 생성부는 switch나 if문을 수정할 수 밖에 없다. 참고로 당연하게도 완전히 만족하도록 짤 수도 있는데(예를들어 옵저버 패턴 등을 적용 / 스프링부트에서도 마찬가지로 OCP를 완전히 만족하도록 주입 및 적용 가능하다.), 역시 당연하게도 코드가 복잡해진다. 즉, 트레이드 오프이다.)
- 객체 생성 과정이 복잡한 경우 객체 생성 프로세스를 캡슐화하고 객체 생성과 사용을 분리하여 코드의 복잡성을 줄이는 팩터리 패턴 사용을 고려할 수 있다.
- 팩터리 패턴의 적용
- 코드에 if 분기 판단 논리가 있으며, 유형에 따라 다른 객체를 동적으로 생성하는 경우 팩터리 패턴을 사용하여 큰 객체 생성 코드를 추출해 팩터리 클래스에 넣는 것을 고려할 수 있다.
- 각 객체의 생성 과정이 상대적으로 복잡한 경우, 팩터리 클래스가 너무 복잡해지는 것을 피하기 위해 팩터리 메서드 패턴을 사용할 수 있다.
- 혹은 유형에 따라 다른 객체를 생성할 필요는 없지만, 단일 객체 자체의 생성 프로세스가 비교적 복잡한 경우에도 적용할 수 있다.
- 팩터리 패턴의 역할
- 생성 과정을 캡슐화 함으로써 생성 과정의 변경 사항이 호출자에게 투명성을 가질 수 있다.
- 생성을 재상죵할 수 있다.
- 생성 과정을 캡슐화하므로, 호출자는 객체 생성 방법을 알 필요가 없다.
- 생성 과정과 사용 과정이 분리되어 복잡한 코드가 간결해진다.
6.5 빌더 패턴
- 생성자를 사용한 객체 생성의 경우 매개변수의 순서나 개수를 잘못 계산하면 잘못된 값을 전달하기 쉽기 때문에 숨겨진 버그가 발생할 수 있다.
- 반면 setter를 통해 모든 값을 설정한다면 모든 값을 설정하기 위해 긴 매개변수를 전부 지정할 필요가 없어 코드의 가독성과 사용 편의성이 훨씬 향상된다.
- 다만 이 경우 다음과 같은 문제점이 있을 수 있다.
- setter 메서드를 통해 설정하면, 필수 항목이 설정되었는지 확인할 방법이 없다.
- 설정 항목 사이에 의존성이 있을 수 있다. (A가 설정되어 있다면 D,Z가 필수로 설정되어야 한다 처럼)
- 클래스의 객체가 불변 객체여야 할 경우 setter 메서드를 노출할 수 없다.
- 위와 같은 문제점을 해결하기 위해 빌더 패턴을 사용한다.
- 빌더 패턴을 사용하여 객체를 생성하면 잘못된 상태의 객체를 방지할 수 있다.
- 빌더 패턴과 팩터리 패턴은 모두 객체 생성 시 사용할 수 있는데, 팩터리 패턴은 동일한 상위 클래스나 인터페이스를 상속하는 하위 클래스 그룹과 같이 유형은 다르지만 연관되어 있는 객체를 생성할 때 사용된다. 빌더 패턴은 동일한 유형의 복잡도가 높은 객체를 생성하는데, 이때 선택적인 매개변수를 설정하거나 사용자 정의를 통해 다른 객체를 생성한다.
'Study > 디자인 패턴의 아름다움' 카테고리의 다른 글
[디자인 패턴의 아름다움] 5. 리팩터링 기법 (1) | 2024.05.17 |
---|---|
[디자인 패턴의 아름다움] 4. 코딩 규칙 - 내용 정리 (0) | 2024.04.24 |
[디자인 패턴의 아름다움] 3. 설계 원칙 - 3.6~3.8 정리 (KISS, YAGNI, DRY, LoD) (0) | 2024.04.24 |
[디자인 패턴의 아름다움] 3. 설계 원칙 - 3.1~3.5 정리 (SOLID) (1) | 2024.04.13 |
[디자인 패턴의 아름다움] 2. 객체지향 프로그래밍 패러다임 - 2.8~2.9 정리 (0) | 2024.04.06 |
댓글