【Golang】设计模式 - Creational - Abstract Factory

Posted by 西维蜀黍 on 2021-09-18, Last Modified on 2023-08-23

Analysis

Abstract Factory Design Pattern is a creational design pattern that lets you create a family of related objects. It is an abstraction over the factory pattern.

Refer to https://swsmile.info/post/design-pattern-factory-pattern/ for Factory pattern.

Demo

Let’s say we have two factories

  • nike
  • adidas

Imagine you need to buy a sports kit which has a shoe and short. Preferably most of the time you would want to buy a full sports kit of a similar factory i.e either nike or adidas. This is where the abstract factory comes into the picture as concrete products that you want is shoe and a short and these products will be created by the abstract factory of nike and adidas. Both these two factories – nike and adidas implement iSportsFactory interface. We have two product interfaces.

  • iShoe – this interface is implemented by nikeShoe and adidasShoe concrete product.
  • iShort – this interface is implemented by nikeShort and adidasShort concrete product.

iSportsFactory.go: Abstract factory interface

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: Concrete factory

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: Concrete factory

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: Abstract product

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: Concrete product

package main

type adidasShoe struct {
    shoe
}

nikeShoe.go: Concrete product

package main

type nikeShoe struct {
    shoe
}

iShirt.go: Abstract product

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: Concrete product

package main

type adidasShirt struct {
    shirt
}

nikeShirt.go: Concrete product

package main

type nikeShirt struct {
    shirt
}

main.go: Client code

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
Logo: nike
Size: 14
Logo: nike
Size: 14
Logo: adidas
Size: 14
Logo: adidas
Size: 14

Reference