1.3. 工厂方法

1.3.1. 目的

相比 简单工厂模式(SimpleFactory)而言,工厂方法模式(Factory Method)可以通过延伸出子类,实现用不同的方法创建对象。

对于比较简单的情况,这个抽象类可能只是一个接口。

这是一个 “真正” 的设计模式,因为它遵循了”依赖反转原则(Dependency Inversion Principle)” 。也就是 SOLID 原则中的”D”。

这意味着工厂方法实现的类依赖于类的抽象,而不是具体的类。这也是 工厂方法模式 与 简单工厂模式 和 静态工厂模式 之间最重要的区别。

1.3.2. UML 图

Alt FactoryMethod UML Diagram

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}