1.3. Metoda wytwórcza (Factory Method)

1.3.1. Przeznaczenie

Przewagą Metody wytwórczej nad Fabryką uproszczoną jest możliwość implementowania różnych sposobów tworzenia obiektów poprzez dziedziczenie po klasie Metody wytwórczej.

W prostych przypadkach zamiast klasy abstrakcyjnej można użyć zwykłego interfejsu.

Ten wzorzec implementuje jedną z podstawowych zasad programowania obiektowego SOLID - „D” - zasadę odwrócenia zależności (ang. Dependency inversion principle).

Oznacza to, że klasa FactoryMethod opiera się na abstrakcji, a nie na konkretnej implementacji. Widać w porównaniu z Fabryką uproszczoną czy Fabryką statyczną.

1.3.2. Diagram UML

Alt FactoryMethod UML Diagram

1.3.3. Kod

Ten kod znajdziesz również na GitHub.

Logger.php

 1<?php
 2
 3declare(strict_types=1);
 4
 5namespace DesignPatterns\Creational\FactoryMethod;
 6
 7interface Logger
 8{
 9    public function log(string $message);
10}

StdoutLogger.php

 1<?php
 2
 3declare(strict_types=1);
 4
 5namespace DesignPatterns\Creational\FactoryMethod;
 6
 7class StdoutLogger implements Logger
 8{
 9    public function log(string $message)
10    {
11        echo $message;
12    }
13}

FileLogger.php

 1<?php
 2
 3declare(strict_types=1);
 4
 5namespace DesignPatterns\Creational\FactoryMethod;
 6
 7class FileLogger implements Logger
 8{
 9    public function __construct(private string $filePath)
10    {
11    }
12
13    public function log(string $message)
14    {
15        file_put_contents($this->filePath, $message . PHP_EOL, FILE_APPEND);
16    }
17}

LoggerFactory.php

 1<?php
 2
 3declare(strict_types=1);
 4
 5namespace DesignPatterns\Creational\FactoryMethod;
 6
 7interface LoggerFactory
 8{
 9    public function createLogger(): Logger;
10}

StdoutLoggerFactory.php

 1<?php
 2
 3declare(strict_types=1);
 4
 5namespace DesignPatterns\Creational\FactoryMethod;
 6
 7class StdoutLoggerFactory implements LoggerFactory
 8{
 9    public function createLogger(): Logger
10    {
11        return new StdoutLogger();
12    }
13}

FileLoggerFactory.php

 1<?php
 2
 3declare(strict_types=1);
 4
 5namespace DesignPatterns\Creational\FactoryMethod;
 6
 7class FileLoggerFactory implements LoggerFactory
 8{
 9    public function __construct(private string $filePath)
10    {
11    }
12
13    public function createLogger(): Logger
14    {
15        return new FileLogger($this->filePath);
16    }
17}

1.3.4. Testy

Tests/FactoryMethodTest.php

 1<?php
 2
 3declare(strict_types=1);
 4
 5namespace DesignPatterns\Creational\FactoryMethod\Tests;
 6
 7use DesignPatterns\Creational\FactoryMethod\FileLogger;
 8use DesignPatterns\Creational\FactoryMethod\FileLoggerFactory;
 9use DesignPatterns\Creational\FactoryMethod\StdoutLogger;
10use DesignPatterns\Creational\FactoryMethod\StdoutLoggerFactory;
11use PHPUnit\Framework\TestCase;
12
13class FactoryMethodTest extends TestCase
14{
15    public function testCanCreateStdoutLogging()
16    {
17        $loggerFactory = new StdoutLoggerFactory();
18        $logger = $loggerFactory->createLogger();
19
20        $this->assertInstanceOf(StdoutLogger::class, $logger);
21    }
22
23    public function testCanCreateFileLogging()
24    {
25        $loggerFactory = new FileLoggerFactory(sys_get_temp_dir());
26        $logger = $loggerFactory->createLogger();
27
28        $this->assertInstanceOf(FileLogger::class, $logger);
29    }
30}