Потрібна крута книжка про патерни та ще й українською? Ось вона »
Фабричний метод

Фабричний метод на Go

Фабричний метод — це породжуючий патерн проектування, який вирішує проблему створення різних продуктів, без прив’язки коду до конкретних класів продуктів.

Фабричний метод задає метод, який необхідно використовувати замість виклику оператора new для створення об’єктів-продуктів. Підкласи можуть перевизначити цей метод, щоб змінювати тип створюваних продуктів.

Якщо ви вже чули про Фабрику, Фабричний метод чи Абстрактну фабрику, але вам все одно важко їх розрізняти, то прочитайте нашу статтю Порівняння фабрик.

Концептуальний приклад

У Go неможливо реалізувати класичний варіант патерна Фабричний метод, оскільки у мові відсутні можливості ООП, у тому числі класи і спадковість. Незважаючи на це, ми все ж можемо реалізувати базову версію цього патерна — Проста фабрика.

У цьому прикладі ми будемо створювати різні типи зброї за допомогою структури фабрики.

Спершу, ми створимо інтерфейс iGun, який визначає всі методи майбутніх гармат. Також маємо структуру gun (гвинтівка), яка застосовує інтерфейс iGun. Дві конкретні гвинтівки — ak47 і musket — обидві включають в себе структуру gun і не безпосередньо реалізують всі методи від iGun.

gunFactory слугує за фабрику, яка створює гвинтівку потрібного типу залежно від аргументу на вході. Клієнтом слугує main.go. Замість прямої взаємодії з об’єктами ak47 або musket, він створює екземпляри різної зброї за допомогою gunFactory, використовуючи для контролю виготовлення тільки параметри у вигляді рядків.

iGun.go: Інтерфейс продукту

package main

type iGun interface {
	setName(name string)
	setPower(power int)
	getName() string
	getPower() int
}

gun.go: Конкретний продукт

package main

type gun struct {
	name  string
	power int
}

func (g *gun) setName(name string) {
	g.name = name
}

func (g *gun) getName() string {
	return g.name
}

func (g *gun) setPower(power int) {
	g.power = power
}

func (g *gun) getPower() int {
	return g.power
}

ak47.go: Конкретний продукт

package main

type ak47 struct {
	gun
}

func newAk47() iGun {
	return &ak47{
		gun: gun{
			name:  "AK47 gun",
			power: 4,
		},
	}
}

musket.go: Конкретний продукт

package main

type musket struct {
	gun
}

func newMusket() iGun {
	return &musket{
		gun: gun{
			name:  "Musket gun",
			power: 1,
		},
	}
}

gunFactory.go: Фабрика

package main

import "fmt"

func getGun(gunType string) (iGun, error) {
	if gunType == "ak47" {
		return newAk47(), nil
	}
	if gunType == "musket" {
		return newMusket(), nil
	}
	return nil, fmt.Errorf("Wrong gun type passed")
}

main.go: Клієнтський код

package main

import "fmt"

func main() {
	ak47, _ := getGun("ak47")
	musket, _ := getGun("musket")

	printDetails(ak47)
	printDetails(musket)
}

func printDetails(g iGun) {
	fmt.Printf("Gun: %s", g.getName())
	fmt.Println()
	fmt.Printf("Power: %d", g.getPower())
	fmt.Println()
}

output.txt: Результат виконання

Gun: AK47 gun
Power: 4
Gun: Musket gun
Power: 1
На основі: Golang By Example

Фабричний метод іншими мовами програмування

Фабричний метод на Java Фабричний метод на C# Фабричний метод на C++ Фабричний метод на PHP Фабричний метод на Python Фабричний метод на Ruby Фабричний метод на Swift Фабричний метод на TypeScript