1

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,

  1. Is this code a valid Flyweight implementation?
  2. Can I use singleton in a Flyweight factory and still be a valid GoF implementation?
  • 4
    Is your desire genuinely to be GOF-Certified™, or is there an actual, practical concern here? Note that the Flyweight already conserves memory; that is its purpose. – Robert Harvey Jul 13 at 17:55
  • It is a flyweight pattern, but it doesn't provide that much benefit. I've typically seen flyweights used in user interfaces where there are a number of repeated constructs (like a grid) that are only needed during the drawing cycle. The important thing there is to render information and move on, so reusing one or two instances will help speed up the rendering process and save a whole lot of memory. – Berin Loritsch Jul 13 at 18:08
  • I am trying to create a free course of GoF Pattern using PHP for portuguese speakers, so yeah, you guys have already had helped me a lot (youtube.com/channel/UC0aGMws3O0PEhxng-CxwLFg?view_as=subscriber) – celsowm Jul 13 at 18:08
2
  1. Is this code a valid Flyweight implementation?

Yes, it is a valid Flyweight implementation, although not where I would have expected to see the Flyweight pattern. But for teaching purposes, that is not a problem.

  1. Can I use singleton in a Flyweight factory and still be a valid GoF implementation?

Yes. The GoF patterns were never meant to stand alone. On the other hand, if your aim is to teach what the Flyweight pattern looks like and how it is used, it is better not to mix other concerns/patterns into that lesson. Unless the students are already familiar with the Singleton pattern and can immediately recognize which parts of the code come from that, I think it would be better to leave the Singleton out.

| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.