Перейти до основного вмісту

3. Фабричний метод (Factory Method)

Призначення

Вигідна відмінність від SimpleFactory в тому, що ви можете винести реалізацію створення об’єктів у підкласи.

У простих випадках цей абстрактний клас може бути тільки інтерфейсом.

Цей патерн є «справжнім» Шаблоном Проєктування, тому що він слідує «Принципу інверсії залежностей» також відомому як «D» в S.O.L.I.D.

Це означає, що клас FactoryMethod залежить від абстракцій, а не від конкретних класів. Це істотний плюс у порівнянні з SimpleFactory або StaticFactory.

Діаграма UML

Factory Method UML

Код

Ви можете знайти цей код на GitHub

Logger.php
<?php

declare(strict_types=1);

namespace DesignPatterns\Creational\FactoryMethod;

interface Logger
{
public function log(string $message);
}
StdoutLogger.php
<?php

declare(strict_types=1);

namespace DesignPatterns\Creational\FactoryMethod;

class StdoutLogger implements Logger
{
public function log(string $message)
{
echo $message;
}
}
FileLogger.php
<?php

declare(strict_types=1);

namespace DesignPatterns\Creational\FactoryMethod;

class FileLogger implements Logger
{
public function __construct(private string $filePath)
{
}

public function log(string $message)
{
file_put_contents($this->filePath, $message . PHP_EOL, FILE_APPEND);
}
}
LoggerFactory.php
<?php

declare(strict_types=1);

namespace DesignPatterns\Creational\FactoryMethod;

interface LoggerFactory
{
public function createLogger(): Logger;
}

StdoutLoggerFactory.php
<?php

declare(strict_types=1);

namespace DesignPatterns\Creational\FactoryMethod;

class StdoutLoggerFactory implements LoggerFactory
{
public function createLogger(): Logger
{
return new StdoutLogger();
}
}
FileLoggerFactory.php
<?php

declare(strict_types=1);

namespace DesignPatterns\Creational\FactoryMethod;

class FileLoggerFactory implements LoggerFactory
{
public function __construct(private string $filePath)
{
}

public function createLogger(): Logger
{
return new FileLogger($this->filePath);
}
}

Тест

Tests/FactoryMethodTest.php
<?php

declare(strict_types=1);

namespace DesignPatterns\Creational\FactoryMethod\Tests;

use DesignPatterns\Creational\FactoryMethod\FileLogger;
use DesignPatterns\Creational\FactoryMethod\FileLoggerFactory;
use DesignPatterns\Creational\FactoryMethod\StdoutLogger;
use DesignPatterns\Creational\FactoryMethod\StdoutLoggerFactory;
use PHPUnit\Framework\TestCase;

class FactoryMethodTest extends TestCase
{
public function testCanCreateStdoutLogging()
{
$loggerFactory = new StdoutLoggerFactory();
$logger = $loggerFactory->createLogger();

$this->assertInstanceOf(StdoutLogger::class, $logger);
}

public function testCanCreateFileLogging()
{
$loggerFactory = new FileLoggerFactory(sys_get_temp_dir());
$logger = $loggerFactory->createLogger();

$this->assertInstanceOf(FileLogger::class, $logger);
}
}