<意图>
【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 );}//检查并存储namefunction getNameFromLine( $line ) { if ( preg_match( "/.*-(.*)\s\d+/", $line, $array ) ) { return str_replace( '_',' ', $array[1] ); } return '';}//检查并存储idfunction 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.'; } //关闭录像机 public function turnOff() { echo 'Turning off the camera.'; } //转到录像机 public function rotate($degrees) { echo 'rotating the camera by ', $degrees, ' degrees.'; }}class Light { //开灯 public function turnOn() { echo 'Turning on the light.'; } //关灯 public function turnOff() { echo 'Turning off the light.'; } //换灯泡 public function changeBulb() { echo 'changing the light-bulb.'; }}class Sensor { //启动感应器 public function activate() { echo 'Activating the sensor.'; } //关闭感应器 public function deactivate() { echo 'Deactivating the sensor.'; } //触发感应器 public function trigger() { echo 'The sensor has been trigged.'; }}class Alarm { //启动警报器 public function activate() { echo 'Activating the alarm.'; } //关闭警报器 public function deactivate() { echo 'Deactivating the alarm.'; } //拉响警报器 public function ring() { echo 'Ring the alarm.'; } //停掉警报器 public function stopRing() { echo 'Stop the alarm.'; }}//门面类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); //只要一个函数就能将调用类简化