For teaching purposes, I am trying to create a "something useful" example of Flyweight pattern using PHP.
My idea was load some "intrinsic" data from a csv (link) to a pool and allow the user to create "cars" (extrinsic) sharing, if possible, the same flyweight data (car model)
To optimize the memory, I thought that a singleton factory would be a good way to avoid duplicates.
<?php
namespace Flyweight;
class Model { //intrínseco (flyweight)
private string $name;
private string $assembler;
public function __construct(string $name, string $assembler) {
$this->name = $name;
$this->assembler = $assembler;
}
public function getName(): string {
return $this->name;
}
public function getAssembler(): string {
return $this->assembler;
}
}
class FlyweightFactory { //fábrica de flyweight (com singleton)
private static $singleton;
private array $flyweights = [];
private function __construct() {
$csv = array_map('str_getcsv', file("vehicles.csv"));
array_walk($csv, function(&$a) use ($csv) {
$a = array_combine($csv[0], $a);
$this->flyweights[] = new Model($a['name'], $a['assembler']);
});
array_unshift($this->flyweights);
}
public static function getInstance(): self {
if (!self::$singleton) {
self::$singleton = new self();
}
return self::$singleton;
}
public function getModel(string $name, string $assembler): Model {
$modelRetorno = array_filter($this->flyweights,
fn(Model $model)
=> $model->getName() == $name && $model->getAssembler() == $assembler);
$modelRetorno = is_array($modelRetorno) ? array_shift($modelRetorno) : null;
if ($modelRetorno == null) {
print("cadastrando novo...");
$modelRetorno = new Model($name, $assembler);
$this->flyweights[] = $modelRetorno;
}
return $modelRetorno;
}
}
class Vehicle { //extrínsico
private string $plate;
private int $year;
private Model $model;
public function __construct(string $plate, int $year, Model $model) {
$this->plate = $plate;
$this->year = $year;
$this->model = $model;
}
public function getPlate(): string {
return $this->plate;
}
public function getYear(): int {
return $this->year;
}
public function getModel(): Model {
return $this->model;
}
}
class VehicleClient { //cliente do flyweight
private array $vehicles;
public function register(string $plate, int $year, string $nameModel, string $assembler) {
$model = FlyweightFactory::getInstance()->getModel($nameModel, $assembler);
$veiculo = new Vehicle($plate, $year, $model);
$this->vehicles[] = $veiculo;
}
public function getAll(): array {
return $this->vehicles;
}
}
$client = new VehicleClient();
$client->register('ABC1234', 1996, "Fiat 147", "FIAT Automobiles S.p.A.");
$client->register('XYB5678', 1998, "Fiat 147", "FIAT Automobiles S.p.A.");
$client->register('NBC9876', 1978, "Gurgel", "Mosantos LTDA");
So,
- Is this code a valid Flyweight implementation?
- Can I use singleton in a Flyweight factory and still be a valid GoF implementation?