1.3. Factory Method

1.3.1. Purpose

The good point over the SimpleFactory is you can subclass it toimplement different ways to create objects.

For simple cases, this abstract class could be just an interface.

This pattern is a “real” Design Pattern because it achieves theDependency Inversion principle a.k.a the “D” in SOLID principles.

It means the FactoryMethod class depends on abstractions, not concreteclasses. This is the real trick compared to SimpleFactory orStaticFactory.

1.3.2. UML Diagram

Alt FactoryMethod UML Diagram

1.3.3. Code

You can also find this code on GitHub

Logger.php

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

StdoutLogger.php

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

FileLogger.php

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

LoggerFactory.php

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

StdoutLoggerFactory.php

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

FileLoggerFactory.php

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

1.3.4. Test

Tests/FactoryMethodTest.php

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