工厂方法模式
目的
与简单工厂模式相比,工厂方法模式的优点是你可以通过子类来实现不同的对象创建方式。
对于简单的情况,这个抽象类可以只是一个接口。
这种模式是一种“真正的”设计模式,因为它实现了依赖倒置原则,也就是 SOLID 原则中的 D。
这意味着 FactoryMethod 类依赖于抽象,而不是具体的类。与简单工厂模式或静态工厂模式相比,这才是真正的技巧。
UML 类图

代码
Logger.php
1 2 3 4 5 6 7 8
| <?php declare(strict_types = 1);
namespace DesignPatterns\Creational\FactoryMethod;
interface Logger { public function log(string $message); }
|
StdoutLogger.php
1 2 3 4 5 6 7 8 9 10 11
| <?php declare(strict_types = 1);
namespace DesignPatterns\Creational\FactoryMethod;
class StdoutLogger implements Logger { public function log(string $message) { echo $message; } }
|
FileLogger.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| <?php declare(strict_types = 1);
namespace DesignPatterns\Creational\FactoryMethod;
class FileLogger implements Logger { private string $filePath;
public function __construct(string $filePath) { $this->filePath = $filePath; }
public function log(string $message) { file_put_contents($this->filePath, $message . PHP_EOL, FILE_APPEND); } }
|
LoggerFactory.php
1 2 3 4 5 6 7 8
| <?php declare(strict_types = 1);
namespace DesignPatterns\Creational\FactoryMethod;
interface LoggerFactory { public function createLogger(): Logger; }
|
StdoutLoggerFactory.php
1 2 3 4 5 6 7 8 9 10 11
| <?php declare(strict_types = 1);
namespace DesignPatterns\Creational\FactoryMethod;
class StdoutLoggerFactory implements LoggerFactory { public function createLogger(): Logger { return new StdoutLogger(); } }
|
FileLoggerFactory
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| <?php declare(strict_types = 1);
namespace DesignPatterns\Creational\FactoryMethod;
class FileLoggerFactory implements LoggerFactory { private string $filePath;
public function __construct(string $filePath) { $this->filePath = $filePath; }
public function createLogger(): Logger { return new FileLogger($this->filePath); } }
|
测试
Tests/FactoryMethodTest.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| <?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); } }
|