【PHP设计模式】结构型之门面(facade)

<意图>
  【GOF】为子系统中的一组接口提供一个一致的界面,Facade模式定义了一个高层次的接口,使得子系统更加容易使用。

  外部与子系统的通信是通过一个门面(Facade)对象进行。

门面模式:

  外部与一个子系统的通信必须通过一个统一的门面对象进行。门面模式提供一个高层次的接口,使得子系统更易于使用。每一个子系统只有一个门面类,而且此门面类只有一个实例,也就是说它是一个单例模式。但整个系统可以有多个门面类。

<UML>

【门面模式的优点】
1、它对客户屏蔽了子系统组件,因而减少了客户处理的对象的数目并使得子系统使用起来更加方便
2、实现了子系统与客户之间的松耦合关系
3、如果应用需要,它并不限制它们使用子系统类。因此可以在系统易用性与能用性之间加以选择

【门面模式适用场景】
1、为一些复杂的子系统提供一组接口
2、提高子系统的独立性
3、在层次化结构中,可以使用门面模式定义系统的每一层的接口

【门面模式与其它模式】
抽象工厂模式:Abstract Factory模式可以与Facade模式一起使用以提供一个接口,这一接口可用来以一种子系统独立的方式创建子系统对象。Abstract Factory模式也可以代替Facade模式隐藏那些与平台相关的类
调停者模式:Mediator模式与Facade模式的相似之处是,它抽象了一些已有类的功能。然而,Mediator目的是对同事之间的任意通讯进行抽象,通常集中不属于任何单个对象的功能。Mediator的同事对象知道中介者并与它通信,而不是直接与其他同类对象通信。相对而言,Facade模式仅对子系统对象的接口进行抽象,从而使它们更容易使用;它并定义不功能,子系统也不知道facade的存在
单例模式:一般来说,仅需要一个Facade对象,因此Facade对象通常属于Singleton对象。

<示例一>获取文件中的log信息并转换成对象数组

//获取文件的内容
function getProductFileLines( $file ) {
    return file( $file );
}

function getProductObjectFromId( $id, $productname ) {
    return new Product( $id, $productname );
}
//检查并存储name
function getNameFromLine( $line ) {
    if ( preg_match( "/.*-(.*)\s\d+/", $line, $array ) ) {
        return str_replace( '_',' ', $array[1] );
    }
    return '';
}
//检查并存储id
function getIDFromLine( $line ) {
    if ( preg_match( "/^(\d{1,3})-/", $line, $array ) ) {
        return $array[1];
    }
    return -1;
}

class Product {
    public $id;
    public $name;
    function __construct( $id, $name ) {
        $this->id = $id;
        $this->name = $name;
    }
}

$lines = getProductFileLines( 'test.txt' );
$objects = array();
foreach ( $lines as $line ) {
    $id = getIDFromLine( $line );
    $name = getNameFromLine( $line );
    $objects[$id] = getProductObjectFromID( $id, $name  );
}

print_r( $objects );

  <UML>

  此时的结构如上图所示。获取文件内容并检查转换成对象数组是个复杂的过程,我们的客户端代码和子系统将会仅仅地耦合在一起。当子系统变化时,或者我们决定将子系统断开时,代码就会出现问题。因此我们的做法应该是在客户端和子系统代码中间建立一个入口。

class ProductFacade {
    private $products = array();

    function __construct( $file ) {
        $this->file = $file;
        $this->compile();
    }

    private function compile() {
        $lines = getProductFileLines( $this->file );
        foreach ( $lines as $line ) {
            $id = getIDFromLine( $line );
            $name = getNameFromLine( $line );
            $this->products[$id] = getProductObjectFromID( $id, $name  );
        }
    } 

    function getProducts() {
        return $this->products;
    }

    function getProduct( $id ) {
        return $this->products[$id];
    }
}
$facade = new ProductFacade( 'test.txt' );
print_r( $facade->getProducts() );
print_r( $facade->getProduct(234) );

<UML>

此时的客户端代码只需要通过门面ProductFacade对象就可以调用了。

<示例二>

class Camera {
    //打开录像机
    public function turnOn() {
        echo 'Turning on the camera.<br />';
    }
     //关闭录像机
    public function turnOff() {
        echo 'Turning off the camera.<br />';
    }
    //转到录像机
    public function rotate($degrees) {
        echo 'rotating the camera by ', $degrees, ' degrees.<br />';
    }
}

class Light {
    //开灯
    public function turnOn() {
        echo 'Turning on the light.<br />';
    }
    //关灯
    public function turnOff() {
        echo 'Turning off the light.<br />';
    }
    //换灯泡
    public function changeBulb() {
        echo 'changing the light-bulb.<br />';
    }
}

class Sensor {
    //启动感应器
    public function activate() {
        echo 'Activating the sensor.<br />';
    }
    //关闭感应器
    public function deactivate() {
        echo 'Deactivating the sensor.<br />';
    }
    //触发感应器
    public function trigger() {
        echo 'The sensor has been trigged.<br />';
    }
}

class Alarm {
    //启动警报器
    public function activate() {
        echo 'Activating the alarm.<br />';
    }
    //关闭警报器
    public function deactivate() {
        echo 'Deactivating the alarm.<br />';
    }
    //拉响警报器
    public function ring() {
        echo 'Ring the alarm.<br />';
    }
    //停掉警报器
    public function stopRing() {
        echo 'Stop the alarm.<br />';
    }
}

//门面类
class SecurityFacade {

    /* 录像机 */
    private $_camera1, $_camera2;

    /**/
    private $_light1, $_light2, $_light3;

    /* 感应器 */
    private $_sensor;

    /* 警报器 */
    private $_alarm;

    public function __construct() {
        $this->_camera1 = new Camera();
        $this->_camera2 = new Camera();

        $this->_light1 = new Light();
        $this->_light2 = new Light();
        $this->_light3 = new Light();

        $this->_sensor = new Sensor();
        $this->_alarm = new Alarm();
    }

    public function activate() {
        $this->_camera1->turnOn();
        $this->_camera2->turnOn();

        $this->_light1->turnOn();
        $this->_light2->turnOn();
        $this->_light3->turnOn();

        $this->_sensor->activate();
        $this->_alarm->activate();
    }

    public  function deactivate() {
        $this->_camera1->turnOff();
        $this->_camera2->turnOff();

        $this->_light1->turnOff();
        $this->_light2->turnOff();
        $this->_light3->turnOff();

        $this->_sensor->deactivate();
        $this->_alarm->deactivate();
    }
}
//客户端
class Client {
    private static $_security;
    public static function main() {
        self::$_security = new SecurityFacade();
        self::$_security->activate();
    }
}
Client::main();

<结果>

Turning on the camera.
Turning on the camera.
Turning on the light.
Turning on the light.
Turning on the light.
Activating the sensor.
Activating the alarm.

 

外观模式:为复杂或多边的系统创建一个简单的接口。

class User { 
     
    protected $userName; 
    protected $userAge; 
     
    public function setUserName($userName) { 
        return $this->userName = $userName; 
    } 
     
    public function setUserAge($userAge) { 
        return $this->userAge = $userAge; 
    } 
     
    public function getUser() { 
        echo '用户姓名:' . $this->userName . '; 用户年龄:' . $this->userAge; 
    } 
} 

 

代码:UserFacade 用户类外观接口,一个getUserCall接口
//创建一个User 类调用接口,简化获取用户getUser方法的调用 

class UserFacade { 
    public static function getUserCall($userInfo) { 
        $User = new User; 
        $User->setUserName($userInfo['username']); 
        $User->setUserAge($userInfo['userAge']); 
        return $User->getUser(); 
    } 
} 

调用:调用的具体执行在外观类中执行,外观类返回一个可以供客户调用的简洁方法,用来获取所需的数据。

$userInfo = array('username' => 'initphp', 'userAge' => 12); 
UserFacade::getUserCall($userInfo); //只要一个函数就能将调用类简化 

posted on 2014-06-22 14:54  color_story  阅读(335)  评论(0编辑  收藏  举报

导航