본문 바로가기

취업과 기본기 튼튼/빽 투더 기본기

[디자인 패턴 17편] 디자인 패턴 총 정리. 생성편

지금까지 공부하며 정리한 GoF 디자인 패턴을 총 정리해보려고 한다.
최대한 간결하고 필요한 것만 남겨본다.

여기서는 구체적인 구현 코드는 적지않고, 이미 패턴이 구현된 객체들을 사용하는 코드만 적겠다.
사용자 코드만 봐도 어떻게 작동하는지 알 수 있을거라 생각한다.
(또 이렇게 사용자 코드만 봐도 이해가 가도록 구현해놓는 코드가 좋은 코드, 패턴이라고 생각한다.)
구현 코드는 대충 참고만할 수 있게, 클래스 다이어그램만 남겨둔다.

먼저 객체의 생성에 대해 다루는 생성편이다.


싱글톤 (Signleton)

코드 내 어디서든, 오직 하나의 인스턴스만 사용할 수 있도록 객체를 생성하는 방법이다.
즉 객체는 여러 번 생성되지 않고, 최초 하나의(Single) 인스턴스만 생성하고, 이후에는 이 인스턴스를 참조하게 된다.
전역적으로 하나의 인스턴스만 사용, 참조해야하는 경우에 사용한다.

사용 예시

# 보통, 싱글톤 객체의 .get_instance() 로 인스턴스를 받아온다.
singleton_1 = Singleton.get_instance()
singleton_2 = Singleton.get_instance()

# 이렇게 받아온 두 인스턴스는 동일한 인스턴스다.
singleton_1 == singleton_2  # True

구현 구조

출처: https://commons.wikimedia.org/wiki/File:Singleton_pattern_uml.png

구체적인 동작은 [디자인 패턴 2편] 생성 패턴, 싱글톤(Singleton) 참고.

활용 예시

  • DB 커넥션과 Pool 을 담당하는 인스턴스
  • 시스템 전역의 로깅을 담당하는 로거

프로토타입 (Prototype)

기존의 인스턴스를 그대로 복제(clone) 하여 새로운 객체를 생성하는 방법이다.
즉, 하나의 인스턴스를 사용하는 싱글톤과는 반대되는 개념이다.

사용 예시

# 보통, 프로토타입 객체의 .clone() 으로 인스턴스를 복사한다.
original = Prototype()
prototype = original.clone()

# 이렇게 받아온 두 인스턴스는 동일한 객체는 아니지만, 내부 데이터는 같다.
original == prototype  # False
original.data == prototype.data  # True

구현 구조

출처 :  https://www.baeldung.com/wp-content/uploads/2019/10/Prototype-Pattern.png

활용 예시

  • DB 로부터 얻어온 데이터 인스턴스를 동일하게 하나 더 만들어야 하는 경우
    • DB 에 연결하는 것 보다 이렇게 코드로 처리 하는게 일반적으로 cost 가 더 저렴하다.
  • 인스턴스 복사가 자주 필요한 어디든..?

팩토리 (Factory)

인스턴스를 만들어내는 공장(Factory) 를 통해 객체를 생성하는 방법이다.
즉, 인스턴스를 직접 생성해내지 않고, 공장에서 제공하는 메쏘드를 통해 생성해낸다.
사용자는 객체를 생성하고 싶을 때, 공장에서 제공하는 메쏘드만 알고있으면 된다.
그 외 구체적으로 인스턴스가 어떻게 생성되는지 몰라도 된다.
한 집합 내에 있는 클래스들의 생성을 한 곳에서 처리하고 싶을 때 사용한다.

사용 예시

# 보통, Factory 객체의 `get` 메쏘드의 파라미터로 생성할 객체의 타입을 넘겨준다.
samsung_keyboard = KeyboardFactory.get_keyboard("samsung")
lg_keyboard = KeyboardFactory.get_keyboard("lg")

# 생성된 객체는 다음과 같이 구체적인 클래스 인스턴스다.
samsung_keyboard  # SamsungKeyboard
lg_keyboard  # LgKeyboard

구현 구조

출처 :  http://fuzzduck.com/Design-Patterns/Factory-Pattern.php

구체적인 동작은 [디자인 패턴 3편] 생성 패턴, 팩토리 메쏘드 (Factory) 참고.

활용 예시

  • 삼성, LG 키보드를 만드는 키보드 팩토리
  • 개념 상 같은 분류의 클래스들의 생성을 모아서 처리하는게 편할 때

추상 팩토리 (Abstract Factory)

공장을 만들어내는 상위 공장을 먼저 정의하고, 여기서 구체적인 공장을 만든 후, 이 공장에서 객체를 생성하는 방법이다.
즉, 팩토리의 위에 이 팩토리를 만드는 팩토리가 있다고 생각하면 된다.
그 외 특징은 팩토리 패턴과 같다.

사용 예시

# 키보드 팩토리의 팩토리(추상 팩토리)를 통해 키보드 팩토리를 얻는다.
CommonKeyboardFactory = AbstarctKeyboardFactory.get_keyboard_factory("common")

# 이후는 팩토리 패턴과 동일하다.
samsung_common_keyboard = CommonKeyboardFactory.get_keyboard("samsung")
lg_common_keyboard = CommonKeyboardFactory.get_keyboard("lg")

samsung_keyboard  # SamsungCommonKeyboard
lg_keyboard  # LgCommonKeyboard

구현 구조

출처 : https://commons.wikimedia.org/wiki/File:Abstract_Factory_UML_class_diagram.svg

구체적인 동작은 [디자인 패턴 5편] 생성 패턴, 추상 팩토리 메쏘드 (Abstract Factory) 참고.

활용 예시

  • 기계식 키보드 공장와 일반 키보드공장을 만드는 키보드 추상 팩토리
  • 팩토리보다 조금 더 복잡한, 혹은 구조적인 계층을 갖는 클래스들의 생성을 처리해야 할 때.

빌더 (Builder)

객체를 생성할 때 필요한 파라미터가 많은 경우, 각 파라미터가 무엇을 의미하는지 알기 힘들 수 있다.
이럴 때, 빌더라는 형태를 통해 파라미터 의미를 명확히하여 생성할 수 있다.
이건 아래의 구체적인 사용 예를 보면 된다.

사용 예시

# 빌더 패턴 사용 전 (경우 1)
WebBrowser browser = WebBrowser(True, FlashPlugin(), True, 10); 

# 빌더 패턴을 사용하면 이렇습니다.
WebBrowser browser = BrowserBuilder().
    with_ssl(True).
    with_flash_plugin().
    with_cookie_support().
    set_timeout(10).
    build()

근데 생각해보니 파이썬에서는 keyword 파라미터를 지원하기 때문에, 굳이 필요 없는 듯 하다.
위 같이 안하고 그냥 다음과 같이 하면 된다.

# 파이썬의 키워드 파라미터 사용
WebBrowser browser = WebBrowser(ssl=True, 
                                flash_plugin=FlashPlugin(), 
                                cookie_support=True,
                                timeout=10)

여러분 파이썬 쓰세요 ~!

구현 구조

출처 : https://ko.m.wikipedia.org/wiki/%ED%8C%8C%EC%9D%BC:Builder_UML_class_diagram.svg

구체적인 동작은 [디자인 패턴 4편] 생성 패턴, 빌더 (Builder) 참고.

활용 예시

  • 파라미터가 너무 많아서 의미를 파악하기 힘들 때

정리

  • 싱글톤, 프로토타입은 완전히 반대의 개념은 아니지만, 비슷한 집합으로 묶을 수 있지 않을 까싶다.
  • 추상 팩토리는 팩토리를 한번 더 요소화 한 것이다.
  • 빌더는 파이썬에서 안써도 될듯 하다.

틀린게 있다면 댓글로 알려주세요 :)