PHP 设计模式系列 —— 门面模式(Facade)

1、模式定义

门面模式(Facade)又称外观模式,用于为子系统中的一组接口提供一个一致的界面。门面模式定义了一个高层接口,这个接口使得子系统更加容易使用:引入门面角色之后,用户只需要直接与门面角色交互,用户与子系统之间的复杂关系由门面角色来实现,从而降低了系统的耦合度。

2、UML类图

Facade-design-pattern

3、示例代码

Facade.php

<?php

namespace DesignPatterns\Structural\Facade;

/**
 * 门面类
 */
class Facade
{
    /**
     * @var OsInterface
     */
    protected $os;

    /**
     * @var BiosInterface
     */
    protected $bios;

    /**
     * This is the perfect time to use a dependency injection container
     * to create an instance of this class
     *
     * @param BiosInterface $bios
     * @param OsInterface   $os
     */
    public function __construct(BiosInterface $bios, OsInterface $os)
    {
        $this->bios = $bios;
        $this->os = $os;
    }

    /**
     * turn on the system
     */
    public function turnOn()
    {
        $this->bios->execute();
        $this->bios->waitForKeyPress();
        $this->bios->launch($this->os);
    }

    /**
     * turn off the system
     */
    public function turnOff()
    {
        $this->os->halt();
        $this->bios->powerDown();
    }
}

OsInterface.php

<?php

namespace DesignPatterns\Structural\Facade;

/**
 * OsInterface接口
 */
interface OsInterface
{
    /**
     * halt the OS
     */
    public function halt();
}

BiosInterface.php

<?php

namespace DesignPatterns\Structural\Facade;

/**
 * BiosInterface接口
 */
interface BiosInterface
{
    /**
     * execute the BIOS
     */
    public function execute();

    /**
     * wait for halt
     */
    public function waitForKeyPress();

    /**
     * launches the OS
     *
     * @param OsInterface $os
     */
    public function launch(OsInterface $os);

    /**
     * power down BIOS
     */
    public function powerDown();
}

4、测试代码

Tests/FacadeTest.php

<?php

namespace DesignPatterns\Structural\Facade\Tests;

use DesignPatterns\Structural\Facade\Facade as Computer;
use DesignPatterns\Structural\Facade\OsInterface;

/**
 * FacadeTest用于测试门面模式
 */
class FacadeTest extends \PHPUnit_Framework_TestCase
{

    public function getComputer()
    {
        $bios = $this->getMockBuilder('DesignPatterns\Structural\Facade\BiosInterface')
                ->setMethods(array('launch', 'execute', 'waitForKeyPress'))
                ->disableAutoload()
                ->getMock();
        $os = $this->getMockBuilder('DesignPatterns\Structural\Facade\OsInterface')
                ->setMethods(array('getName'))
                ->disableAutoload()
                ->getMock();
        $bios->expects($this->once())
                ->method('launch')
                ->with($os);
        $os->expects($this->once())
                ->method('getName')
                ->will($this->returnValue('Linux'));

        $facade = new Computer($bios, $os);
        return array(array($facade, $os));
    }

    /**
     * @dataProvider getComputer
     */
    public function testComputerOn(Computer $facade, OsInterface $os)
    {
        // interface is simpler :
        $facade->turnOn();
        // but I can access to lower component
        $this->assertEquals('Linux', $os->getName());
    }
}

5、总结

门面模式对客户屏蔽子系统组件,因而减少了客户处理的对象的数目并使得子系统使用起来更加方便;实现了子系统与客户之间的松耦合关系,而子系统内部的功能组件往往是紧耦合的,松耦合关系使得子系统的组件变化不会影响到它的客户;如果应用需要,门面模式并不限制客户程序使用子系统类,因此你可以让客户程序在系统易用性和通用性之间加以选择。

Laravel 中门面模式的使用也很广泛,基本上每个服务容器中注册的服务提供者类都对应一个门面类。

学院君 has written 880 articles

Laravel学院院长,终身学习者

积分:99492 等级:P12 职业:码农 城市:杭州

11 条回复

  1. M天街小雨 M天街小雨 says:
    lavavel的facade就是在门面类中加了一个callstatic用静态方法方便直接调用,省去了写new的步骤而已,跟这个确实没关系
  2. FN9 FN9 says:
    sorry,没看到 use DesignPatterns\Structural\Facade\Facade as Computer; 这个
  3. FN9 FN9 says:
    Tests/FacadeTest.php中的 $facade = new Computer($bios, $os); 在原文中是 $facade = new Facade($bios, $os);
  4. 一周时间苦学设计模式 一周时间苦学设计模式 says:
    怎么感觉这里讲的门面模式例子与Laravel Facades不是一回事啊,看完这个门面模式好像对理解Laravel Facades没起什么作用。。。囧,尴尬
  5. oliver oliver says:
    @ 李虎啸 因为不论是哪种模式,最终的目的都差不多,绝大部分都是为了松耦合
  6. 伟洋 伟洋 says:
    为什么感觉每种模式都是那么相似,简单工厂模式也是实现了子系统与客户之间的松耦合关系。。

登录后才能进行评论,立即登录?