/ Gists / 13. Flyweight
On gists

13. Flyweight

Navrhove vzory - Bohmer

flyweight.php Raw #

<?php

/*

Návrhový vzor Flyweight zabezpečuje společné využívání velmi podobných objektů,
aby je bylo možné použít ve velkém počtu bez nárůstu spotřeby paměti.

Při implementaci návrhového vzoru Flyweight to neznamená, že příslušné třídy
nesmějí obsahovat žádný atribut, který by uchovával jejich stav. Při implementaci
se rozlišuje mezi vnitřním (nebo též vlastní – angl. intrinsic) a vnějším (nebo též
nevlastní – angl. extrinsic) stavem. Vnitřní stav návrhový vzor i nadále uchovává
a obsahuje výlučně informace, které jsou nezávislé na obsahu. Vnější stav je závislý
na obsahu, a proto jej nelze uchovávat a společně využívat ve třídách návrhového
vzoru Flyweight.


Definice
----------
Návrhový vzor Flyweight zabezpečuje společné využívání velmi podobných objektů,
aby je bylo možné použít ve velkém počtu bez nárůstu spotřeby paměti.

Pro implementaci návrhového vzoru Flyweight jsou nutné následující kroky:

1. Identifikovat třídu, z níž se vytváří velké množství instancí.
2. Tuto třídu osvobodit od co největšího počtu objektů, které uchovávají stav
konkrétní implementace. Tento stav instancí uložit někde mimo instance.
3. Implementovat třídu, která slouží jako zástupce „mušího“ objektu.

*/


// optimalizace pro Muší vahu :), kod z Factory kap. 3

// OLD
abstract class Cell
{
    protected $content = null;
    public function __construct($content)
    {
        $this->content = $content;
    }
    abstract public function show();
}
// NEW
abstract class Cell 
{
    abstract public function show($data);
}


// OLD
class TextCell extends Cell 
{
    public function show() 
    {
        $diff = strlen($this->content) -  mb_strlen($this->content, 'UTF-8');
        print '|' . str_pad($this->content, 15 + $diff);
    }
}


// NEW
class TextCell extends Cell
{
    public function show($data)
    {
        $diff = strlen($data) - mb_strlen($data, 'UTF-8');
        print '|' . str_pad($data, 15 + $diff);
    }
}


// OLD
interface TableFactory 
{
    public function createCell($content);
    public function createRow();
    public function createHeader();
    public function createTable();
}
// NEW
interface TableFactory 
{
    public function createCell();
    public function createRow();
    public function createHeader();
    public function createTable();
}


// OLD
abstract class Row 
{
    protected $cellData = array();
    
    public function addCell($cell) 
    {
        $this->cellData[] = $cell;
    }
    
    abstract public function show();
}
// NEW
abstract class Row
{
    protected $cellData = array();
    protected $flyWeightCell;
    
    public function __construct(Cell $cell)
    {
        $this->flyWeightCell = $cell;
    }
    // ... ostatní metody třídy
}


// OLD
class TextRow extends Row
{
    public function show()
    {
        foreach ($this->cells as $cell) {
            $cell->show();
        }

        print "|\n";
        $str = '';
        for ($i = 0; $i < count($this->cells); $i++) {
            $str .= '+' . str_repeat('-', 15);
        }

        print $str . "+\n";
    }
}
// NEW
class TextRow extends Row
{
    public function show()
    {
        foreach ($this->cellData as $data) {
            $this->flyWeightCell->show($data);
        }
        print "|\n";
        $str = '';
        for ($i = 0; $i < count($this->cellData); $i++) {
            $str .= '+' . str_repeat('-', 15);
        }
        print $str . "+\n";
    }
}


// OLD
class TextHeader extends Header
{
    public function show()
    {
        $str = '';
        for ($i = 0; $i < count($this->cells); $i++) 
        {
            $str .= '+' . str_repeat('-', 15);
        }

        print $str . "+\n";

        foreach ($this->cells as $cell) 
        {
            $cell->show();
        }

        print "|\n";
        print $str . "+\n";
    }
}
// NEW
class TextHeader extends Header
{
    public function show() 
    {
        $str = '';
        for ($i = 0; $i < count($this->cellData); $i++) 
        {
            $str .= '+' . str_repeat('-',15);
        }

        print $str . "+\n";

        foreach ($this->cellData as $data) 
        {
            $this->flyWeightCell->show($data);
        }

        print "|\n";
        print $str . "+\n";
    }
}


// OLD
class TextTableFactory implements TableFactory
{
    public function createCell($content)
    {
        return new TextCell($content);
    }
    public function createRow()
    {
        return new TextRow();
    }
    public function createHeader()
    {
        return new TextHeader();
    }
    public function createTable()
    {
        return new TextTable();
    }
}
// NEW
class TextTableFactory implements TableFactory
{
    private $cell = null;
    public function createCell()
    {
        if (null === $this->cell) {
            $this->cell = new TextCell();
        }
        return $this->cell;
    }
    public function createRow()
    {
        $row = new TextRow($this->createCell());
        return $row;
    }
    public function createHeader()
    {
        $header = new TextHeader($this->createCell());
        return $header;
    }
    public function createTable()
    {
        return new TextTable();
    }
}


// OLD
class PublicationList
{
    protected $tableFactory = null;
    public function __construct(TableFactory $tf)
    {
        $this->tableFactory = $tf;
    }
    public function displayTable($data)
    {
        $table = $this->tableFactory->createTable();

        $header = $this->tableFactory->createHeader();
        $header->addCell($this->tableFactory->createCell('Kategorie'));
        $header->addCell($this->tableFactory->createCell('Počet stran'));

        $table->setHeader($header);

        foreach ($data as $line) {
            $row = $this->tableFactory->createRow();
            foreach ($line as $field) {
                $cell = $this->tableFactory->createCell($field);
                $row->addCell($cell);
            }
            $table->addRow($row);
        }
        $table->show();
    }
}
// NEW
class PublicationList
{
    protected $tableFactory = null;
    public function __construct(TableFactory $tf)
    {
        $this->tableFactory = $tf;
    }
    public function displayTable($data)
    {
        $table = $this->tableFactory->createTable();
        
        $header = $this->tableFactory->createHeader();
        $header->addCell('Kategorie');
        $header->addCell('Počet stran');

        $table->setHeader($header);

        foreach ($data as $line) {
            $row = $this->tableFactory->createRow();
            $table->addRow($row);
            foreach ($line as $field) {
                $row->addCell($field);
            }
        }
        $table->show();
    }
}


// USAGE, stale stejne jen se zmenil pocet objektů
/*

Tam, kde se v původní implementaci používaly rozdílné instance třídy cz\k1886\
tables\text\TextCell, jsou nyní všude odkazy na stejnou instanci. 

Tuto skutečnost můžete vidět na čísle za instancí. V tomto případě je to #5. Místo osmi
instancí této třídy tedy potřebujete už jen jednu, čímž jste zredukovali počet
potřebných instancí o 87,5 %.

Je samozřejmé, že můžete v redukování objektů pokračovat i dále a použít muší
váhu i na objekty řádků tabulky


*/
$publications = array(
    array('PC', 100),
    array('PC', 380),
    array('medicína', 250),
    array('historie', 70),
    );
$pl = new PublicationList(new TextTableFactory());
$pl->displayTable($publications);