겨울 세일!
추상 팩토리

Go로 작성된 추상 팩토리

추상 팩토리는 생성 디자인 패턴이며, 관련 객체들의 구상 클래스들을 지정하지 않고도 해당 객체들의 제품 패밀리들을 생성할 수 있도록 합니다.

추상 팩토리는 모든 고유한 제품들을 생성하기 위한 인터페이스를 정의하지만 실제 제품 생성은 구상 팩토리 클래스들에 맡깁니다. 또 각 팩토리 유형은 특정 제품군에 해당합니다.

클라이언트 코드는 생성자 호출​(new 연산자)​로 직접 제품들을 생성하는 대신 팩토리 객체의 생성 메서드들을 호출합니다. 팩토리는 단일 제품 변형에 해당하므로 해당 팩토리의 모든 제품이 호환될 것입니다.

클라이언트 코드는 추상 인터페이스를 통해서만 팩토리 및 제품과 함께 작동하며, 이렇게 하면 클라이언트 코드가 팩토리 객체에 의해 생성된 모든 제품 변형과 함께 작동할 수 있습니다. 새로운 구상 팩토리 클래스를 생성한 후 클라이언트 코드에 전달합니다.

다양한 팩토리 패턴들과 개념들의 차이점을 이해하지 못하셨다면 팩토리 비교를 읽어보세요.

개념적인 예시

신발과 셔츠라는 두 가지 제품으로 구성된 스포츠 키트를 구매해야 한다고 가정해 봅시다. 모든 아이템이 일치하도록 같은 브랜드의 완전한 스포츠 키트를 구매하시고 싶으실 것입니다.

이것을 코드로 바꾸면 추상 팩토리는 제품들이 항상 서로 일치하는 제품 세트들을 만들 수 있습니다.

iSportsFactory.go: 추상 팩토리 인터페이스

package main

import "fmt"

type ISportsFactory interface {
	makeShoe() IShoe
	makeShirt() IShirt
}

func GetSportsFactory(brand string) (ISportsFactory, error) {
	if brand == "adidas" {
		return &Adidas{}, nil
	}

	if brand == "nike" {
		return &Nike{}, nil
	}

	return nil, fmt.Errorf("Wrong brand type passed")
}

adidas.go: 구상 팩토리

package main

type Adidas struct {
}

func (a *Adidas) makeShoe() IShoe {
	return &AdidasShoe{
		Shoe: Shoe{
			logo: "adidas",
			size: 14,
		},
	}
}

func (a *Adidas) makeShirt() IShirt {
	return &AdidasShirt{
		Shirt: Shirt{
			logo: "adidas",
			size: 14,
		},
	}
}

nike.go: 구상 팩토리

package main

type Nike struct {
}

func (n *Nike) makeShoe() IShoe {
	return &NikeShoe{
		Shoe: Shoe{
			logo: "nike",
			size: 14,
		},
	}
}

func (n *Nike) makeShirt() IShirt {
	return &NikeShirt{
		Shirt: Shirt{
			logo: "nike",
			size: 14,
		},
	}
}

iShoe.go: 추상 제품

package main

type IShoe interface {
	setLogo(logo string)
	setSize(size int)
	getLogo() string
	getSize() int
}

type Shoe struct {
	logo string
	size int
}

func (s *Shoe) setLogo(logo string) {
	s.logo = logo
}

func (s *Shoe) getLogo() string {
	return s.logo
}

func (s *Shoe) setSize(size int) {
	s.size = size
}

func (s *Shoe) getSize() int {
	return s.size
}

adidasShoe.go: 구상 제품

package main

type AdidasShoe struct {
	Shoe
}

nikeShoe.go: 구상 제품

package main

type NikeShoe struct {
	Shoe
}

iShirt.go: 추상 제품

package main

type IShirt interface {
	setLogo(logo string)
	setSize(size int)
	getLogo() string
	getSize() int
}

type Shirt struct {
	logo string
	size int
}

func (s *Shirt) setLogo(logo string) {
	s.logo = logo
}

func (s *Shirt) getLogo() string {
	return s.logo
}

func (s *Shirt) setSize(size int) {
	s.size = size
}

func (s *Shirt) getSize() int {
	return s.size
}

adidasShirt.go: 구상 제품

package main

type AdidasShirt struct {
	Shirt
}

nikeShirt.go: 구상 제품

package main

type NikeShirt struct {
	Shirt
}

main.go: 클라이언트 코드

package main

import "fmt"

func main() {
	adidasFactory, _ := GetSportsFactory("adidas")
	nikeFactory, _ := GetSportsFactory("nike")

	nikeShoe := nikeFactory.makeShoe()
	nikeShirt := nikeFactory.makeShirt()

	adidasShoe := adidasFactory.makeShoe()
	adidasShirt := adidasFactory.makeShirt()

	printShoeDetails(nikeShoe)
	printShirtDetails(nikeShirt)

	printShoeDetails(adidasShoe)
	printShirtDetails(adidasShirt)
}

func printShoeDetails(s IShoe) {
	fmt.Printf("Logo: %s", s.getLogo())
	fmt.Println()
	fmt.Printf("Size: %d", s.getSize())
	fmt.Println()
}

func printShirtDetails(s IShirt) {
	fmt.Printf("Logo: %s", s.getLogo())
	fmt.Println()
	fmt.Printf("Size: %d", s.getSize())
	fmt.Println()
}

output.txt: 실행 결과

Logo: nike
Size: 14
Logo: nike
Size: 14
Logo: adidas
Size: 14
Logo: adidas
Size: 14

다른 언어로 작성된 추상 팩토리

C#으로 작성된 추상 팩토리 C++로 작성된 추상 팩토리 자바로 작성된 추상 팩토리 PHP로 작성된 추상 팩토리 파이썬으로 작성된 추상 팩토리 루비로 작성된 추상 팩토리 러스트로 작성된 추상 팩토리 스위프트로 작성된 추상 팩토리 타입스크립트로 작성된 추상 팩토리