合规国际互联网加速 OSASE为企业客户提供高速稳定SD-WAN国际加速解决方案。 广告
# 适配器模式(Adapter) 适配器(Adapter)模式:将一个类的接口转换成客户希望的另外一个接口,使得原本由于接口不兼容而不能一起工作的那些类能一起工作。 > 适配器模式分为类结构型模式和对象结构型模式两种,前者类之间的耦合度比后者高,且要求程序员了解现有组件库中的相关组件的内部结构,所以应用相对较少些。 **该模式的主要优点如下。** - 客户端通过适配器可以透明地调用目标接口。 - 复用了现存的类,程序员不需要修改原有代码而重用现有的适配者类。 - 将目标类和适配者类解耦,解决了目标类和适配者类接口不一致的问题。 **其缺点是:** 对类适配器来说,更换适配器的实现过程比较复杂。 应用场景:老代码接口不适应新的接口需求,或者代码很多很乱不便于继续修改,或者使用第三方类库。 想使用一个已存在的类,但是该类不符合接口需求;或者需要创建一个可重用的类,适配没有提供合适接口的其它类。 一句话总结:不改变原有类的情况下对其进行改造 ## **①第一种方式:对象适配器** ``` <pre class="calibre10">``` <span class="token">//老的接口代码 </span> class <span class="token4">User</span> <span class="token3">{</span> private $name<span class="token3">;</span> <span class="token5">function</span> <span class="token4">__construct</span><span class="token3">(</span>$name<span class="token3">)</span> <span class="token3">{</span> $this<span class="token1">-</span><span class="token1">></span>name <span class="token1">=</span> $name<span class="token3">;</span> <span class="token3">}</span> public <span class="token5">function</span> <span class="token4">getName</span><span class="token3">(</span><span class="token3">)</span> <span class="token3">{</span> <span class="token5">return</span> $this<span class="token1">-</span><span class="token1">></span>name<span class="token3">;</span> <span class="token3">}</span> <span class="token3">}</span> <span class="token">//新代码,开放平台标准接口 </span> interface <span class="token4">UserInterface</span> <span class="token3">{</span> <span class="token5">function</span> <span class="token4">getUserName</span><span class="token3">(</span><span class="token3">)</span><span class="token3">;</span> <span class="token3">}</span> class <span class="token4">UserInfo</span> implements <span class="token4">UserInterface</span> <span class="token3">{</span> protected $user<span class="token3">;</span> <span class="token5">function</span> <span class="token4">__construct</span><span class="token3">(</span>$user<span class="token3">)</span> <span class="token3">{</span> $this<span class="token1">-</span><span class="token1">></span>user <span class="token1">=</span> $user<span class="token3">;</span> <span class="token3">}</span> public <span class="token5">function</span> <span class="token4">getUserName</span><span class="token3">(</span><span class="token3">)</span> <span class="token3">{</span> <span class="token5">return</span> $this<span class="token1">-</span><span class="token1">></span>user<span class="token1">-</span><span class="token1">></span><span class="token4">getName</span><span class="token3">(</span><span class="token3">)</span><span class="token3">;</span> <span class="token3">}</span> <span class="token3">}</span> $olduser <span class="token1">=</span> <span class="token5">new</span> <span class="token4">User</span><span class="token3">(</span><span class="token2">'张三'</span><span class="token3">)</span><span class="token3">;</span> echo $olduser<span class="token1">-</span><span class="token1">></span><span class="token4">getName</span><span class="token3">(</span><span class="token3">)</span><span class="token3">.</span><span class="token2">"n"</span><span class="token3">;</span><span class="token">//张三n </span> $newuser <span class="token1">=</span> <span class="token5">new</span> <span class="token4">UserInfo</span><span class="token3">(</span>$olduser<span class="token3">)</span><span class="token3">;</span> echo $newuser<span class="token1">-</span><span class="token1">></span><span class="token4">getUserName</span><span class="token3">(</span><span class="token3">)</span><span class="token3">.</span><span class="token2">"n"</span><span class="token3">;</span><span class="token">//张三n </span> ``` ``` > **注意点**: > 这里的新接口使用了组合方式,UserInfo内部有一个成员变量保存老接口User对象,模块之间是松耦合的,这种结构其实就是组合模式。不要使用继承,虽然UserInfo继承User也能达到同样的目的,但是耦合度高,相互产生影响。 新能源汽车的发动机有电能发动机(Electric Motor)和光能发动机(Optical Motor)等,各种发动机的驱动方法不同,例如,电能发动机的驱动方法 electricDrive() 是用电能驱动,而光能发动机的驱动方法 opticalDrive() 是用光能驱动,它们是适配器模式中被访问的适配者。 客户端希望用统一的发动机驱动方法 drive() 访问这两种发动机,所以必须定义一个统一的目标接口 Motor,然后再定义电能适配器(Electric Adapter)和光能适配器(Optical Adapter)去适配这两种发动机 ``` <pre class="calibre10">``` <span class="token">//目标:发动机</span> interface <span class="token4">Motor</span> <span class="token3">{</span> public <span class="token5">function</span> <span class="token4">drive</span><span class="token3">(</span><span class="token3">)</span><span class="token3">;</span> <span class="token3">}</span> <span class="token">//适配者1:电能发动机</span> class <span class="token4">ElectricMotor</span> <span class="token3">{</span> public <span class="token5">function</span> <span class="token4">electricDrive</span><span class="token3">(</span><span class="token3">)</span> <span class="token3">{</span> echo <span class="token2">"电能发动机驱动汽车!"</span><span class="token3">;</span> <span class="token3">}</span> <span class="token3">}</span> <span class="token">//适配者2:光能发动机</span> class <span class="token4">OpticalMotor</span> <span class="token3">{</span> public <span class="token5">function</span> <span class="token4">opticalDrive</span><span class="token3">(</span><span class="token3">)</span> <span class="token3">{</span> echo <span class="token2">"光能发动机驱动汽车!"</span><span class="token3">;</span> <span class="token3">}</span> <span class="token3">}</span> <span class="token">//电能适配器</span> class <span class="token4">ElectricAdapter</span> implements <span class="token4">Motor</span> <span class="token3">{</span> private $emotor<span class="token3">;</span> public <span class="token5">function</span> <span class="token4">ElectricAdapter</span><span class="token3">(</span><span class="token3">)</span> <span class="token3">{</span> $this<span class="token1">-</span><span class="token1">></span>emotor<span class="token1">=</span><span class="token5">new</span> <span class="token4">ElectricMotor</span><span class="token3">(</span><span class="token3">)</span><span class="token3">;</span> <span class="token3">}</span> public <span class="token5">function</span> <span class="token4">drive</span><span class="token3">(</span><span class="token3">)</span> <span class="token3">{</span> $this<span class="token1">-</span><span class="token1">></span>emotor<span class="token1">-</span><span class="token1">></span><span class="token4">electricDrive</span><span class="token3">(</span><span class="token3">)</span><span class="token3">;</span> <span class="token3">}</span> <span class="token3">}</span> <span class="token">//光能适配器</span> class <span class="token4">OpticalAdapter</span> implements <span class="token4">Motor</span> <span class="token3">{</span> private $omotor<span class="token3">;</span> public <span class="token5">function</span> <span class="token4">OpticalAdapter</span><span class="token3">(</span><span class="token3">)</span> <span class="token3">{</span> $this<span class="token1">-</span><span class="token1">></span>omotor<span class="token1">=</span><span class="token5">new</span> <span class="token4">OpticalMotor</span><span class="token3">(</span><span class="token3">)</span><span class="token3">;</span> <span class="token3">}</span> public <span class="token5">function</span> <span class="token4">drive</span><span class="token3">(</span><span class="token3">)</span> <span class="token3">{</span> $this<span class="token1">-</span><span class="token1">></span>omotor<span class="token1">-</span><span class="token1">></span><span class="token4">opticalDrive</span><span class="token3">(</span><span class="token3">)</span><span class="token3">;</span> <span class="token3">}</span> <span class="token3">}</span> <span class="token">//客户端代码</span> class <span class="token4">MotorAdapterTest</span> <span class="token3">{</span> public static <span class="token5">function</span> <span class="token4">main</span><span class="token3">(</span>$class<span class="token3">)</span> <span class="token3">{</span> echo <span class="token2">"适配器模式测试:"</span><span class="token3">;</span> $motor<span class="token1">=</span><span class="token5">new</span> $<span class="token4">class</span><span class="token3">(</span><span class="token3">)</span><span class="token3">;</span> $motor<span class="token1">-</span><span class="token1">></span><span class="token4">drive</span><span class="token3">(</span><span class="token3">)</span><span class="token3">;</span> <span class="token3">}</span> <span class="token3">}</span> MotorAdapterTest<span class="token3">:</span><span class="token3">:</span><span class="token4">main</span><span class="token3">(</span><span class="token2">"ElectricAdapter"</span><span class="token3">)</span><span class="token3">;</span> MotorAdapterTest<span class="token3">:</span><span class="token3">:</span><span class="token4">main</span><span class="token3">(</span><span class="token2">"OpticalAdapter"</span><span class="token3">)</span><span class="token3">;</span> ``` ``` ## **②第二种方式:类适配器** ![](https://img.kancloud.cn/56/ab/56abbf41f2d0aa10ab9b9340857e0d9b_639x326.png) ``` <pre class="calibre10">``` <span class="token">//目标接口</span> interface <span class="token4">Target</span> <span class="token3">{</span> public <span class="token5">function</span> <span class="token4">request</span><span class="token3">(</span><span class="token3">)</span><span class="token3">;</span> <span class="token3">}</span> <span class="token">//适配者接口</span> class <span class="token4">Adaptee</span> <span class="token3">{</span> public <span class="token5">function</span> <span class="token4">specificRequest</span><span class="token3">(</span><span class="token3">)</span> <span class="token3">{</span> echo <span class="token2">"适配者中的业务代码被调用!"</span><span class="token3">;</span> <span class="token3">}</span> <span class="token3">}</span> <span class="token">//类适配器类</span> class <span class="token4">ClassAdapter</span> extends <span class="token4">Adaptee</span> implements <span class="token4">Target</span> <span class="token3">{</span> public <span class="token5">function</span> <span class="token4">request</span><span class="token3">(</span><span class="token3">)</span> <span class="token3">{</span> $this<span class="token1">-</span><span class="token1">></span><span class="token4">specificRequest</span><span class="token3">(</span><span class="token3">)</span><span class="token3">;</span> <span class="token3">}</span> <span class="token3">}</span> <span class="token">//客户端代码</span> class <span class="token4">ClassAdapterTest</span> <span class="token3">{</span> public static <span class="token5">function</span> <span class="token4">main</span><span class="token3">(</span><span class="token3">)</span> <span class="token3">{</span> echo <span class="token2">"类适配器模式测试:"</span><span class="token3">;</span> $target <span class="token1">=</span> <span class="token5">new</span> <span class="token4">ClassAdapter</span><span class="token3">(</span><span class="token3">)</span><span class="token3">;</span> $target<span class="token1">-</span><span class="token1">></span><span class="token4">request</span><span class="token3">(</span><span class="token3">)</span><span class="token3">;</span> <span class="token3">}</span> <span class="token3">}</span> ClassAdapterTest<span class="token3">:</span><span class="token3">:</span><span class="token4">main</span><span class="token3">(</span><span class="token3">)</span><span class="token3">;</span> ``` ``` ``` <pre class="calibre10">``` interface <span class="token4">Target2</span> <span class="token3">{</span> public <span class="token5">function</span> <span class="token4">sampleMethod1</span><span class="token3">(</span><span class="token3">)</span><span class="token3">;</span> public <span class="token5">function</span> <span class="token4">sampleMethod2</span><span class="token3">(</span><span class="token3">)</span><span class="token3">;</span> <span class="token3">}</span> class <span class="token4">Adaptee1</span> <span class="token3">{</span> <span class="token">// 源角色</span> public <span class="token5">function</span> <span class="token4">sampleMethod1</span><span class="token3">(</span><span class="token3">)</span> <span class="token3">{</span>echo <span class="token2">'++++++++'</span><span class="token3">;</span><span class="token3">}</span> <span class="token3">}</span> class <span class="token4">Adapter2</span> extends <span class="token4">Adaptee1</span> implements <span class="token4">Target2</span> <span class="token3">{</span> <span class="token">// 适配后角色</span> public <span class="token5">function</span> <span class="token4">sampleMethod2</span><span class="token3">(</span><span class="token3">)</span> <span class="token3">{</span>echo <span class="token2">'————————'</span><span class="token3">;</span><span class="token3">}</span> <span class="token3">}</span> $adapter <span class="token1">=</span> <span class="token5">new</span> <span class="token4">Adapter2</span><span class="token3">(</span><span class="token3">)</span><span class="token3">;</span> $adapter<span class="token1">-</span><span class="token1">></span><span class="token4">sampleMethod1</span><span class="token3">(</span><span class="token3">)</span><span class="token3">;</span><span class="token">//输出:++++++++</span> $adapter<span class="token1">-</span><span class="token1">></span><span class="token4">sampleMethod2</span><span class="token3">(</span><span class="token3">)</span><span class="token3">;</span><span class="token">//输出:————————</span> ``` ``` ## **模式的扩展**:双向适配器模式 双向适配器类既可以把适配者接口转换成目标接口,也可以把目标接口转换成适配者接口 ![](https://img.kancloud.cn/8c/58/8c5862955e4082b51a4a8d4a5a87bceb_499x608.png) ``` <pre class="calibre17">``` <span class="token">//目标接口</span> interface <span class="token4">TwoWayTarget</span> <span class="token3">{</span> public <span class="token5">function</span> <span class="token4">request</span><span class="token3">(</span><span class="token3">)</span><span class="token3">;</span> <span class="token3">}</span> <span class="token">//适配者接口</span> interface <span class="token4">TwoWayAdaptee</span> <span class="token3">{</span> public <span class="token5">function</span> <span class="token4">specificRequest</span><span class="token3">(</span><span class="token3">)</span><span class="token3">;</span> <span class="token3">}</span> <span class="token">//目标实现</span> class <span class="token4">TargetRealize</span> implements <span class="token4">TwoWayTarget</span> <span class="token3">{</span> public <span class="token5">function</span> <span class="token4">request</span><span class="token3">(</span><span class="token3">)</span> <span class="token3">{</span> echo <span class="token2">"目标代码被调用!"</span><span class="token3">;</span> <span class="token3">}</span> <span class="token3">}</span> <span class="token">//适配者实现</span> class <span class="token4">AdapteeRealize</span> implements <span class="token4">TwoWayAdaptee</span> <span class="token3">{</span> public <span class="token5">function</span> <span class="token4">specificRequest</span><span class="token3">(</span><span class="token3">)</span> <span class="token3">{</span> echo <span class="token2">"适配者代码被调用!"</span><span class="token3">;</span> <span class="token3">}</span> <span class="token3">}</span> <span class="token">//双向适配器</span> class <span class="token4">TwoWayAdapter</span> implements <span class="token4">TwoWayTarget</span><span class="token3">,</span>TwoWayAdaptee <span class="token3">{</span> private $target<span class="token3">;</span> private $adaptee<span class="token3">;</span> public <span class="token5">function</span> <span class="token4">__construct</span><span class="token3">(</span>$class<span class="token3">)</span><span class="token3">{</span> <span class="token5">if</span> <span class="token3">(</span>$class <span class="token4">instanceof</span> TwoWayTarget<span class="token3">)</span> <span class="token3">{</span> $this<span class="token1">-</span><span class="token1">></span>target<span class="token1">=</span>$class<span class="token3">;</span> <span class="token3">}</span> <span class="token5">if</span> <span class="token3">(</span>$class <span class="token4">instanceof</span> TwoWayAdaptee<span class="token3">)</span> <span class="token3">{</span> $this<span class="token1">-</span><span class="token1">></span>adaptee<span class="token1">=</span>$class<span class="token3">;</span> <span class="token3">}</span> <span class="token3">}</span> public <span class="token5">function</span> <span class="token4">request</span><span class="token3">(</span><span class="token3">)</span> <span class="token3">{</span> $this<span class="token1">-</span><span class="token1">></span>adaptee<span class="token1">-</span><span class="token1">></span><span class="token4">specificRequest</span><span class="token3">(</span><span class="token3">)</span><span class="token3">;</span> <span class="token3">}</span> public <span class="token5">function</span> <span class="token4">specificRequest</span><span class="token3">(</span><span class="token3">)</span> <span class="token3">{</span> $this<span class="token1">-</span><span class="token1">></span>target<span class="token1">-</span><span class="token1">></span><span class="token4">request</span><span class="token3">(</span><span class="token3">)</span><span class="token3">;</span> <span class="token3">}</span> <span class="token3">}</span> <span class="token">//客户端代码</span> class <span class="token4">TwoWayAdapterTest</span> <span class="token3">{</span> public static <span class="token5">function</span> <span class="token4">main</span><span class="token3">(</span><span class="token3">)</span> <span class="token3">{</span> echo <span class="token2">"目标通过双向适配器访问适配者:"</span><span class="token3">;</span> $adaptee<span class="token1">=</span><span class="token5">new</span> <span class="token4">AdapteeRealize</span><span class="token3">(</span><span class="token3">)</span><span class="token3">;</span> $target<span class="token1">=</span><span class="token5">new</span> <span class="token4">TwoWayAdapter</span><span class="token3">(</span>$adaptee<span class="token3">)</span><span class="token3">;</span> $target<span class="token1">-</span><span class="token1">></span><span class="token4">request</span><span class="token3">(</span><span class="token3">)</span><span class="token3">;</span> echo <span class="token2">"-------------------"</span><span class="token3">;</span> echo <span class="token2">"适配者通过双向适配器访问目标:"</span><span class="token3">;</span> $target<span class="token1">=</span><span class="token5">new</span> <span class="token4">TargetRealize</span><span class="token3">(</span><span class="token3">)</span><span class="token3">;</span> $adaptee<span class="token1">=</span><span class="token5">new</span> <span class="token4">TwoWayAdapter</span><span class="token3">(</span>$target<span class="token3">)</span><span class="token3">;</span> $adaptee<span class="token1">-</span><span class="token1">></span><span class="token4">specificRequest</span><span class="token3">(</span><span class="token3">)</span><span class="token3">;</span> <span class="token3">}</span> <span class="token3">}</span> TwoWayAdapterTest<span class="token3">:</span><span class="token3">:</span><span class="token4">main</span><span class="token3">(</span><span class="token3">)</span><span class="token3">;</span> ``` ```