外观模式
目的
外观模式,也称为门面模式,其主要目的不是为了避免你必须阅读复杂的 API 手册,这只是顺带的事儿。它的主要目标是减少耦合,并遵循迪米特法则。
门面(Facade)的意思是通过置入大量接口(但有时候只有一个)来解耦客户端和子系统,当然,这种做法也是为了降低复杂性。
- 门面并不禁止您访问子系统
- 你可以(应该)为一个子系统设置多个门面
这就是为什么一个好的「门面」不存在 new
这种写法。如果每个方法都有多种创建方式,那么,它就不是外观模式,而是一个构造者模式,或者是抽象工厂/静态工厂/简单工厂模式中的一种。
最佳实践是,Facade 没有 new
关键字,也没有带接口类型提示参数的构造函数。如果你需要创建新的实例,请使用一个 Factory
作为参数。
UML 类图

代码
Facade.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\Structural\Facade;
class Facade { private OperatingSystem $os; private Bios $bios;
public function __construct(Bios $bios, OperatingSystem $os) { $this->bios = $bios; $this->os = $os; }
public function turnOn() { $this->bios->execute(); $this->bios->waitForKeyPress(); $this->bios->launch($this->os); }
public function turnOff() { $this->os->halt(); $this->bios->powerDown(); } }
|
OperatingSystem.php
1 2 3 4 5 6 7 8 9 10
| <?php declare(strict_types = 1);
namespace DesignPatterns\Structural\Facade;
interface OperatingSystem { public function halt();
public function getName(): string; }
|
Bios.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| <?php declare(strict_types = 1);
namespace DesignPatterns\Structural\Facade;
interface Bios { public function execute();
public function waitForKeyPress();
public function launch(OperatingSystem $os);
public function powerDown(); }
|
测试
Tests/FacadeTest.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 30
| <?php declare(strict_types = 1);
namespace DesignPatterns\Structural\Facade\Tests;
use DesignPatterns\Structural\Facade\Bios; use DesignPatterns\Structural\Facade\Facade; use DesignPatterns\Structural\Facade\OperatingSystem; use PHPUnit\Framework\TestCase;
class FacadeTest extends TestCase { public function testComputerOn() { $os = $this->createMock(OperatingSystem::class);
$os->method('getName') ->will($this->returnValue('Linux'));
$bios = $this->createMock(Bios::class);
$bios->method('launch') ->with($os);
$facade = new Facade($bios, $os); $facade->turnOn();
$this->assertSame('Linux', $os->getName()); } }
|