1.3. 工厂方法
1.3.1. 目的
相比 简单工厂模式(SimpleFactory)而言,工厂方法模式(Factory Method)可以通过延伸出子类,实现用不同的方法创建对象。
对于比较简单的情况,这个抽象类可能只是一个接口。
这是一个 “真正” 的设计模式,因为它遵循了”依赖反转原则(Dependency Inversion Principle)” 。也就是 SOLID 原则中的”D”。
这意味着工厂方法实现的类依赖于类的抽象,而不是具体的类。这也是 工厂方法模式 与 简单工厂模式 和 静态工厂模式 之间最重要的区别。
1.3.2. UML 图

1.3.3. 代码
你可以在 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. 测试
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}