目录: D:\bridge Mode LastWriteTime Length Name ---- ------------- ------ ---- -a---- 2021/9/16 10:19 276 EatByChopsticks.php -a---- 2021/9/16 10:19 270 EatByFork.php -a---- 2021/9/16 10:19 200 EatInterface.php -a---- 2021/9/16 10:19 654 PersonAbstract.php -a---- 2021/9/16 10:19 276 PersonMale.php -a---- 2021/9/16 10:19 962 test.php
<?php namespace bridge; # 吃接口 interface EatInterface { # 吃 @param string $food 食物 public function eat($food=''); }
<?php namespace bridge; # 用筷子吃实体 class EatByChopsticks implements EatInterface { # 吃 @param string $food 食物 public function eat($food='') { echo "用筷子吃{$food}~"; } }
<?php namespace bridge; # 用叉子吃实体 class EatByFork implements EatInterface { # 吃 public function eat($food='') { echo "用叉子吃{$food}~"; } }
<?php namespace bridge; # 人抽象类 abstract class PersonAbstract { # 性别 protected $_gender = ''; # 使用的吃饭工具 protected $_tool = ''; # 构造函数 @param string $gender 性别 public function __construct($gender='',EatInterface $tool) { $this->_gender = $gender; $this->_tool = $tool; } # 吃的行为 @param string $food 实物 abstract public function eat($food=''); }
<?php namespace bridge; # 男人实类 class PersonMale extends PersonAbstract { # 吃的具体方式 @param string $food 食物 public function eat($food='') { $this->_tool->eat($food); } }
结构型模式
运行 php test.php
// 注册自加载 spl_autoload_register('autoload'); function autoload($class) { require dirname($_SERVER['SCRIPT_FILENAME']).'//..//'.str_replace('\\','/',$class).'.php'; } /************************************* test *************************************/ use bridge\PersonMale; use bridge\EatByChopsticks; use bridge\EatByFork; try { // 初始化一个用筷子吃饭的男人的实例 $male = new PersonMale('male', new EatByChopsticks()); // 吃饭 $male->eat('大盘鸡'); } catch (\Exception $e) { echo $e->getMessage(); }
php test.php 用筷子吃大盘鸡~
try { // 初始化一个用筷子吃饭的男人的实例 $male = new PersonMale('male', new EatByFork()); // 吃饭 $male->eat('大盘鸡'); } catch (\Exception $e) { echo $e->getMessage(); }
用叉子吃大盘鸡~
1 、使用接口(interface),可以指定某个类必须实现哪些方法,但不需要定义这些方法的具体内容。
2、接口是通过 interface 关键字来定义的,就像定义一个标准的类一样,但其中定义所有的方法都是空的。
3、 接口中定义的所有方法都必须是公有,这是接口的特性。
需要注意的是:
在接口中定义一个构造方法是被允许的。在有些场景下这可能会很有用,例如用于工厂模式时。
1、类中必须实现接口中定义的所有方法,否则会报一个致命错误。
2、类可以实现多个接口,用逗号来分隔多个接口的名称。
注意:
接口也可以继承,通过使用 extends
操作符。
类要实现接口,必须使用和接口中所有定义的方法完全一致的方式。否则会导致致命错误。
接口中也可以定义常量。
接口中常量和类常量的使用完全相同,但是不能被子类或子接口所覆盖。
尽管不能再接口中包含变量,但是可以包含常量。要使用常量,需要用到 “作用域解析操作符” 即是双冒号::
。
示例:使用接口常量的一般格式
$someVariable = InterfaceName::SOME_CONSTANT;
接口文件 IConnectInfo.php
<?php interface IConnectInfo { // 定义常量 const HOST = "localhost"; const UNAME = "root"; const DBNAME = "wqzbxh"; const PW = "root"; function testConnection(); }
使用接口文件 ConSQL.php
<?php //引入IConnectInfo接口 include_once('IConnectInfo.php'); Class ConSQL implements IConnectInfo { private $server = IConnectInfo::HOST; private $currenDB = IConnectInfo::DBNAME; private $user = IConnectInfo::UNAME; private $password = IConnectInfo::PW; public function testConnection() { // TODO: Implement testConnection() method. try{ $hookup = new mysqli($this->server,$this->user,$this->password,$this->currenDB); if(mysqli_connect_errno()){ die('connection fail!'); } echo "You are hooked Up Ace!<br/>".$hookup->host_info; $hookup->close(); }catch (Exception $e){ echo $e->getMessage(); } } } $useConstant = new ConSQL(); $useConstant->testConnection();
php .\ConSQL.php You are hooked Up Ace!<br/>localhost via TCP/IP
这里面接口文件只有一个testconnection
方法,但是如果愿意接口中也可以只包含变量不包含任何方法。
定义为抽象的类不能被实例化。
任何一个类,如果里面有一个方法是被声明为抽象的,那么这个类就必须被声明为抽象的。
被定义为抽象的方法只是声明了其调用方式(参数),不能定义其具体的功能实现。
继承一个抽象类的时候,子类必须定义父类中的所有抽象方法;
另外,这些方法的访问控制必须和父类中一样(或者更为宽松)。
例如某个抽象方法被声明为受保护的,
那么子类中实现的方法就应该声明为受保护的或者公有的,而不能定义为私有的。
此外方法的调用方式必须匹配,即类型和所需参数数量必须一致。
<?php abstract class AbstractClass { //强制要求子类定义这些方法 abstract protected function getValue(); abstract protected function prefixValue($prefix); //普通方法非抽象方法 public function printout(){ print $this->getValue()."\n"; } } class ChildAbstract extends AbstractClass{ protected function getValue(){ return "ChildAbstract"; } public function prefixValue($prefix){ return $prefix."ChildAbstract"; } } $class1 = new ChildAbstract; $class1->printout(); echo PHP_EOL.$class1->prefixValue('FOO_'); /*运行结果 ChildAbstract FOO_ChildAbstract */