Глянь мій новий курс по Git! Привіт! Глянь мій новий курс по Git! Привіт! Глянь мій новий курс по Git на GitByBit.com! Привіт! Хочеш класно освіжити Git? Глянь мій новий курс на GitByBit.com!
Легковаговик

Легковаговик на Go

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

Легковаговик дозволяє економити пам’ять, записуючи в кеш однакові дані, що використовуються різними об’єктами.

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

У грі Counter-Strike Терористи і Контртерористи мають різні типи мундира. Для спрощення припустимо, що і Терористи, і Контртерористи мають по одному типу мундира. Об’єкт «мундир» вписаний в об’єкт «гравець» наступним чином:

Нижче наведена структура гравця. Як бачимо, об’єкт «мундир» вписаний в структуру гравця:

type player struct {
    dress      dress
    playerType string // Може бути T або CT
    lat        int
    long       int
}

Припустимо, що у нас є 5 Терористів і 5 Контртерористів, тобто всього 10 гравців. Тоді ми маємо два можливих варіанти створення мундирів:

  1. Кожен з 10 об’єктів гравців створює окремий об’єкт мундира і вбудовує його. Всього створюється 10 об’єктів мундирів.

  2. Ми створюємо 2 об’єкти мундирів:

    - Єдиний Об’єкт Мундира Терориста — його будуть використовувати 5 Терористів. - Єдиний Об’єкт Мундира Контртерориста – його будуть використовувати 5 Контртерористів.

Як ми бачимо, у Варіанті 1 доведеться створити 10 об’єктів мундирів, тоді як у Варіанті 2 ми створюємо лише 2 об’єкти. Другий підхід — це суть патерна проектування Легковаговик. Два об’єкти мундирів, створені нами, називають легковаговими об’єктами.

Патерн Легковаговик знаходить однакові елементи і створює легковагові об’єкти. Ці легковагові об’єкти (мундири) в подальшому можуть бути поширені між декількома об’єктами (гравці). Така практика значно зменшує кількість об’єктів мундирів, а головне — навіть якщо ми створимо більше гравців, їм однаково буде достатньо лише двох об’єктів мундирів.

Використовуючи патерн Легковаговик, ми зберігаємо легковагові об’єкти в полях карти. Коли створюються інші об’єкти, що розділяють між собою легковагові об’єкти, легковаговики завантажуються з карти.

Тепер давайте подумаємо над тим, які частини цієї системи будуть входити до «внутрішнього» або «зовнішнього стану»:

  • Внутрішній стан: Мундир належить до внутрішнього стану, оскільки він використовується декількома об’єктами Терористів і Контртерористів.

  • Зовнішній стан: Місцезнаходження та зброя гравця належать до зовнішнього стану, оскільки у кожного об’єкта вони різні.

dressFactory.go: Фабрика легковаговиків

package main

import "fmt"

const (
	//TerroristDressType terrorist dress type
	TerroristDressType = "tDress"
	//CounterTerrroristDressType terrorist dress type
	CounterTerrroristDressType = "ctDress"
)

var (
	dressFactorySingleInstance = &DressFactory{
		dressMap: make(map[string]Dress),
	}
)

type DressFactory struct {
	dressMap map[string]Dress
}

func (d *DressFactory) getDressByType(dressType string) (Dress, error) {
	if d.dressMap[dressType] != nil {
		return d.dressMap[dressType], nil
	}

	if dressType == TerroristDressType {
		d.dressMap[dressType] = newTerroristDress()
		return d.dressMap[dressType], nil
	}
	if dressType == CounterTerrroristDressType {
		d.dressMap[dressType] = newCounterTerroristDress()
		return d.dressMap[dressType], nil
	}

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

func getDressFactorySingleInstance() *DressFactory {
	return dressFactorySingleInstance
}

dress.go: Інтерфейс легковаговиків

package main

type Dress interface {
	getColor() string
}

terroristDress.go: Конкретний легковаговик

package main

type TerroristDress struct {
	color string
}

func (t *TerroristDress) getColor() string {
	return t.color
}

func newTerroristDress() *TerroristDress {
	return &TerroristDress{color: "red"}
}

counterTerroristDress.go: Конкретний легковаговик

package main

type CounterTerroristDress struct {
	color string
}

func (c *CounterTerroristDress) getColor() string {
	return c.color
}

func newCounterTerroristDress() *CounterTerroristDress {
	return &CounterTerroristDress{color: "green"}
}

player.go: Контекст

package main

type Player struct {
	dress      Dress
	playerType string
	lat        int
	long       int
}

func newPlayer(playerType, dressType string) *Player {
	dress, _ := getDressFactorySingleInstance().getDressByType(dressType)
	return &Player{
		playerType: playerType,
		dress:      dress,
	}
}

func (p *Player) newLocation(lat, long int) {
	p.lat = lat
	p.long = long
}

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

package main

type game struct {
	terrorists        []*Player
	counterTerrorists []*Player
}

func newGame() *game {
	return &game{
		terrorists:        make([]*Player, 1),
		counterTerrorists: make([]*Player, 1),
	}
}

func (c *game) addTerrorist(dressType string) {
	player := newPlayer("T", dressType)
	c.terrorists = append(c.terrorists, player)
	return
}

func (c *game) addCounterTerrorist(dressType string) {
	player := newPlayer("CT", dressType)
	c.counterTerrorists = append(c.counterTerrorists, player)
	return
}

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

package main

import "fmt"

func main() {
	game := newGame()

	//Add Terrorist
	game.addTerrorist(TerroristDressType)
	game.addTerrorist(TerroristDressType)
	game.addTerrorist(TerroristDressType)
	game.addTerrorist(TerroristDressType)

	//Add CounterTerrorist
	game.addCounterTerrorist(CounterTerrroristDressType)
	game.addCounterTerrorist(CounterTerrroristDressType)
	game.addCounterTerrorist(CounterTerrroristDressType)

	dressFactoryInstance := getDressFactorySingleInstance()

	for dressType, dress := range dressFactoryInstance.dressMap {
		fmt.Printf("DressColorType: %s\nDressColor: %s\n", dressType, dress.getColor())
	}
}

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

DressColorType: ctDress
DressColor: green
DressColorType: tDress
DressColor: red
На основі: Golang By Example

Легковаговик іншими мовами програмування

Легковаговик на C# Легковаговик на C++ Легковаговик на Java Легковаговик на PHP Легковаговик на Python Легковаговик на Ruby Легковаговик на Rust Легковаговик на Swift Легковаговик на TypeScript