본문 바로가기
  • Dev Blog
CS/디자인 패턴

[GoF 디자인 패턴] - 추상 팩토리 메서드 패턴

by 유진영 2024. 5. 28.
모든 코드는 Swift로 작성되었습니다.

 

문제 상황

https://jeonyeohun.tistory.com/386

 

BlackView, BlackButton, YellowView, YellowButton 객체들을 조합하여 위 그림과 같은 조합의 객체를 생성해야 하는 상황이라고 가정해 보자.

 

각 객체들을 팩토리 메서드 패턴을 사용해서 생성하고자 한다면 아래 그림과 같이 BlackView와 YellowView는 View의 Concrete Product로 하고 ColoredViewFactory라는 Concrete Creator를 생성할 것이고, BlackButton과 YellowButton은 Button의 Concrete Product, ColoredButtonFactory를 Concrete Creator로 생성할 것이다.

 

https://jeonyeohun.tistory.com/386

 

하지만, 팩토리 메서드 패턴을 사용한다면, BlackView와 YellowButton의 조합 또는 YellowView와 BlackButton의 조합을 보장할 순 없을 것이다.

 

 

추상 팩토리 메서드 패턴

추상 팩토리 메서드 패턴은 팩토리 메서드 패턴 사용 중 서로 관련 있는 객체의 집합을 생성하고자 할 때 사용되는 디자인 패턴이다. 아래 그림과 같이 View와 Button의 Creator들을 한번 더 추상화함으로써 조합이 보장될 수 있게 해 준다. (그림에서 DarkButtonBoxFactory를 BlackViewYellowButtonFactory, LightButtonBoxFactory를 YellowViewBlackButtonFactory로 생각하면 이해하기 쉽다.)

 

https://jeonyeohun.tistory.com/386

 

코드 예시

Product와 Concrete Product

더보기
// ================= Product =================

protocol View {
  func getViewColor() -> String
}

protocol Button {
  func getButtonColor() -> String
}

// ================= Concrete Product =================

class YellowView: View {
  private var viewColor = "Yellow"

  func getViewColor() -> String {
    return self.viewColor + "View"
  }
}

class BlackView: View {
  private var viewColor = "Black"

  func getViewColor() -> String {
    return self.viewColor + "View"
  }
}

class YellowButton: Button {
  private var buttonColor = "Yellow"

  func getButtonColor() -> String {
    return self.buttonColor + "Button"
  }
}

class BlackButton: Button {
  private var buttonColor = "Black"

  func getButtonColor() -> String {
    return self.buttonColor + "Button"
  }
}

 

Creator와 Concrete Creator

더보기
protocol ViewButtonFactory { // Creator
  func createView() -> View
  func createButton() -> Button
}

class BlackViewYellowButtonFactory: ViewButtonFactory { // Concrete Creator
  func createView() -> View {
    return BlackView()
  }
  func createButton() -> Button {
    return YellowButton()
  }
}

class YellowViewBlackButtonFactory: ViewButtonFactory { // Concrete Creator
  func createView() -> View {
    return YellowView()
  }
  func createButton() -> Button {
    return BlackButton()
  }
}

 

클라이언트 객체 코드 예시

더보기
class ButtonBox {
  private var viewButtonFacotry: ViewButtonFactory
  private var button: Button
  private var view: View

  init(_ viewButtonFactory: ViewButtonFactory) {
    self.viewButtonFacotry = viewButtonFactory
    self.button = viewButtonFacotry.createButton()
    self.view = viewButtonFacotry.createView()
  }

  func change(viewButtonFactory: ViewButtonFactory) {
    self.viewButtonFacotry = viewButtonFactory
    self.button = viewButtonFacotry.createButton()
    self.view = viewButtonFacotry.createView()
  }

  func printComponents() {
      print(self.view.getViewColor())
      print(self.button.getButtonColor())
  }
}

var buttonBox = ButtonBox(BlackViewYellowButtonFactory())
buttonBox.printComponents()
// Black View
// Yellow Button

print("\n## Change Factory ##\n")

buttonBox.change(YellowViewBlackButtonFactory())
buttonBox.printComponents()
// Yellow View
// Black Button

 

 

장점

팩토리 메서드 패턴처럼 개방-폐쇄 원칙을 준수할 수 있음과 동시에 팩토리 메서드 패턴이 해결하지 못하는 객체 조합 보장 문제를 해결할 수 있다.

 

단점

만약, Concrete Prouct의 종류에 변동이 생긴다면 기존의 Concrete Creator 코드를 수정해야 하는 상황이 발생할 수 있다.  

댓글