SOLDES de printemps
Poids mouche

Poids mouche en Go

Le poids mouche est un patron de conception structurel qui permet à des programmes de limiter leur consommation de mémoire malgré un très grand nombre d’objets.

Ce patron est obtenu en partageant des parties de l’état d’un objet à plusieurs autres objets. En d’autres termes, le poids mouche économise de la RAM en mettant en cache les données identiques chez différents objets.

Exemple conceptuel

Dans une partie de Counter-Strike, les terroristes et les contre-terroristes sont habillés différemment. Pour faire plus simple, disons que chaque camp n’a qu’un seul type de tenue. L’objet Tenue est imbriqué dans l’objet joueur comme ci-dessous.

Voici la struct pour un joueur. Nous pouvons observer que la tenue est imbriquée dans la struct joueur :

type player struct {
    dress      dress
    playerType string // Peut être un T ou CT
    lat        int
    long       int
}

Prenons 5 terroristes et 5 contre-terroristes, donc 10 joueurs au total. Nous avons maintenant 2 possibilités pour les tenues.

  1. Chacun des 10 objets joueur crée un objet tenue différent et l’imbrique. Au total, 10 objets tenue seront créés.

  2. Nous créons deux objets tenue :

    • Un unique objet tenue pour terroriste. Il sera partagé entre les 5 terroristes.
    • Un unique objet tenue pour contre-terroriste. Il sera partagé entre les 5 contre-terroristes.

Comme vous pouvez le constater, dans la première approche, un total de 10 objets tenue sont créés, alors que dans la seconde, on se contente de deux. La seconde approche est celle suggérée par le patron de conception poids mouche. Les deux objets tenue que nous avons créés s’appellent les objets poids mouche.

Le patron de conception poids mouche retire les morceaux communs et crée des objets poids mouche. Ces objets (tenues) peuvent ensuite être partagés entre de multiples objets (joueurs). Nous réduisons ainsi drastiquement le nombre d’objets tenue et de plus, même si vous ajoutez plus de joueurs, les deux objets tenue restent suffisants.

Dans le patron poids mouche, nous stockons les objets poids mouche dans l’attribut de la table de hachage. Dès que d’autres objets qui partagent ces objets poids mouche sont créés, ces derniers sont récupérés depuis la table de hachage.

Regardons quelles parties de ce dispositif seront les états intrinsèques et extrinsèques :

  • État intrinsèque : La tenue fait partie de l’état intrinsèque, car elle peut être partagée entre plusieurs terroristes ou contre-terroristes.

  • État extrinsèque : La position de chaque joueur et son arme font partie de l’état extrinsèque, car elles sont différentes pour chaque objet.

dressFactory.go: Fabrique poids mouche

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: Interface poids mouche

package main

type Dress interface {
	getColor() string
}

terroristDress.go: Objet poids mouche concret

package main

type TerroristDress struct {
	color string
}

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

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

counterTerroristDress.go: Objet poids mouche concret

package main

type CounterTerroristDress struct {
	color string
}

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

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

player.go: Contexte

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: Code client

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: Code client

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: Résultat de l’exécution

DressColorType: ctDress
DressColor: green
DressColorType: tDress
DressColor: red

Poids mouche dans les autres langues

Poids mouche en C# Poids mouche en C++ Poids mouche en Java Poids mouche en PHP Poids mouche en Python Poids mouche en Ruby Poids mouche en Rust Poids mouche en Swift Poids mouche en TypeScript