工厂方法模式(Factory Method)

目的

对比简单工厂模式的优点是,您可以将其子类用不同的方法来创建一个对象。

举一个简单的例子,这个抽象类可能只是一个接口。

这种模式是「真正」的设计模式, 因为他实现了S.O.L.I.D原则中「D」的 「依赖倒置」。

这意味着工厂方法模式取决于抽象类,而不是具体的类。 这是与简单工厂模式和静态工厂模式相比的优势。

UML 图

file

代码

你可以在 GitHub 查看这段代码

Logger.php

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

StdoutLogger.php

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

FileLogger.php

  1. <?php
  2. namespace DesignPatterns\Creational\FactoryMethod;
  3. class FileLogger implements Logger
  4. {
  5. /**
  6. * @var string
  7. */
  8. private $filePath;
  9. public function __construct(string $filePath)
  10. {
  11. $this->filePath = $filePath;
  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. namespace DesignPatterns\Creational\FactoryMethod;
  3. interface LoggerFactory
  4. {
  5. public function createLogger(): Logger;
  6. }

StdoutLoggerFactory.php

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

FileLoggerFactory.php

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

测试

Tests/FactoryMethodTest.php

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