适配器模式很常用的;商城中的例子比如快递发货,那么多种快递公司;可能每个快递公司的接口对接都不一样都要适配;比如各种框架中的类似以下思想的代码,都是为了适配。
public function behaviors()
{
return array_merge(parent::behaviors(), [
'login' => [
'class' => LoginBehavior::className(),
],
]);
}
适配器出现的原因:将一个类的接口转换成客户希望的另外一个接口。Adapter模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作
整个适配链的角色:
①目标角色:也就是我们希望得到的数据结构。
②源角色:需要进行适配的接口 (比如顺丰、中通、蜂鸟等他们的接口的数据结构都不一样;我们如果想要接通他们在我们平台可以使用;那就需要与他们对接后,把数据结构统一!)
③适配器:其实就相当与一个工具类,把源改造成 目标
哪些场景适合使用适配器呢?
1.你想使用一个已存在的类;但是它的数据结构已经不能满足你的需求了
2.或者说你想复用一个类(因为此类可能封装了很多底层的东西,你不清楚但也不敢改动),这是可以创建一个新类 拓展类
3.你想使用一个已经存在的子类,但是不可能对每一个都进行子类化以匹配它们的接口。对象适配器可以适配它的父类接口(仅限于对象适配器)
1、类适配器
//目标角色 接口类
interface ITarget
{
function operation1();
function operation2();
}
//源角色 接口类
interface IAdaptee
{
function operation1();
}
//源角色 实现 源接口类
class Adaptee implements IAdaptee
{
public function operation1()
{
echo "原方法";
}
}
//适配器角色 (把源改造成我们想要的)
class Adapter extends Adaptee implements IAdaptee, ITarget
{
public function operation2()
{
echo "适配方法";
}
}
//我们想要的数据;看=》目标角色 接口类 就可以知道我们需要的是2个方法
class Client
{
public function test()
{
$adapter = new Adapter();
$adapter->operation1();//原方法
$adapter->operation2();//适配方法
}
}
2.对象适配器
//目标角色
interface ITarget
{
function operation1();
function operation2();
}
//源角色
interface IAdaptee
{
function operation1();
}
class Adaptee implements IAdaptee
{
public function operation1()
{
echo "原方法";
}
}
//适配器角色 (这样的代码是否可以优化?如果ITarget目标接口类想要N个方法呢?在这里都一个一个写上?)
class Adapter implements ITarget
{
private $adaptee;
public function __construct($adaptee)
{
$this->adaptee = $adaptee;
}
public function operation1()
{
return $this->adaptee->operation1();
}
public function operation2()
{
echo "适配方法";
}
}
class Client
{
public function test()
{
$adapter = new Adapter(new Adaptee(null));
$adapter->operation1();//原方法
$adapter->operation2();//适配方法
}
}
可以看出对象适配器比类适配器灵活一点的,但是还可以优化,比如使用php的__call方法;
//改造前
class Adapter implements ITarget
{
private $adaptee;
public function __construct($adaptee)
{
$this->adaptee = $adaptee;
}
public function operation1()
{
return $this->adaptee->operation1();
}
public function operation2()
{
echo "适配方法";
}
....N个方法
}
//改造后
class Adapter implements ITarget
{
private $adaptee;
public function __construct($adaptee)
{
$this->adaptee = $adaptee;
}
//当实例化调用不存在的方法是 自动调用
public function __call($func, $args)
{
if (is_callable(array($this->adaptee, $func))) {
return $this->adaptee->$func($args);
}
trigger_error('*********', E_USER_ERROR);
}
}