静态工厂模式

目的

和抽象工厂模式类似,静态工厂模式是用于创建一系列相关的或相互依赖的对象。和抽象工厂模式不同的地方在于,静态工厂模式仅通过一个静态方法来创建它能创建的所有类型的对象。它通常被命名为 factory 或者 build

UML 类图

静态工厂模式类图

代码

StaticFactory.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<?php declare(strict_types = 1);

namespace DesignPatterns\Creational\StaticFactory;

use InvalidArgumentException;

/**
* Note1: Remember, static means global state which is evil because it can't be mocked for tests
* Note2: Cannot be subclassed or mock-upped or have multiple different instances.
*/
final class StaticFactory
{
public static function factory(string $type): Formatter
{
if ($type == 'number') {
return new FormatNumber();
} elseif ($type == 'string') {
return new FormatString();
}

throw new InvalidArgumentException('Unknown format given');
}
}

Formatter.php

1
2
3
4
5
6
7
8
<?php declare(strict_types = 1);

namespace DesignPatterns\Creational\StaticFactory;

interface Formatter
{
public function format(string $input): string;
}

FormatString.php

1
2
3
4
5
6
7
8
9
10
11
<?php declare(strict_types = 1);

namespace DesignPatterns\Creational\StaticFactory;

class FormatString implements Formatter
{
public function format(string $input): string
{
return $input;
}
}

FormatNumber.php

1
2
3
4
5
6
7
8
9
10
11
<?php declare(strict_types = 1);

namespace DesignPatterns\Creational\StaticFactory;

class FormatNumber implements Formatter
{
public function format(string $input): string
{
return number_format((int) $input);
}
}

测试

Tests/StaticFactoryTest.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
29
<?php declare(strict_types = 1);

namespace DesignPatterns\Creational\StaticFactory\Tests;

use InvalidArgumentException;
use DesignPatterns\Creational\StaticFactory\FormatNumber;
use DesignPatterns\Creational\StaticFactory\FormatString;
use DesignPatterns\Creational\StaticFactory\StaticFactory;
use PHPUnit\Framework\TestCase;

class StaticFactoryTest extends TestCase
{
public function testCanCreateNumberFormatter()
{
$this->assertInstanceOf(FormatNumber::class, StaticFactory::factory('number'));
}

public function testCanCreateStringFormatter()
{
$this->assertInstanceOf(FormatString::class, StaticFactory::factory('string'));
}

public function testException()
{
$this->expectException(InvalidArgumentException::class);

StaticFactory::factory('object');
}
}