Adapter Pattern

适配器模式Adapter的作用是将一个类的接口转换成客户希望的另外一个接口,使用原本不兼容的而不能在一起工作的那些类可以在一起工作,用好此模式可以使程序易于扩展,当你的代码依赖于一些外部的API时可以尝试使用适配器模式,适配器模式同样也适用于某些变动频繁的类,废话不多说,以一个支付api的例子来看一下:

未使用适配器

Alipay

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
<?php
namespace App;

class Alipay
{
    public function __construct() {
        // ...
    }

    public function sendPayment($amount) {
        echo "支付宝付款: ". $amount;
    }
}

Wxpay

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
<?php
namespace App;

class Wxpay
{
    public function __construct() {
        // ...
    }

    public function doPayment($amount) {
        echo "微信支付: ". $amount;
    }
}

客户端调用

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
<?php

namespace App;

class ClientOld
{

    public function alipay()
    {
        $alipay = new Alipay();
        $alipay->sendPayment(100);
    }

    public function wxpay()
    {
        $alipay = new  Wxpay();
        $alipay->doPayment(100);
    }

}

使用适配器后

PayAdapter

1
2
3
4
5
6
<?php
namespace App;

interface PayAdapter{
    public  function pay($amount);
}

Alipay

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
<?php
namespace App;

class Alipay
{
    public function __construct() {
        // ...
    }

    public function sendPayment($amount) {
        echo "支付宝付款: ". $amount;
    }
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
<?php
namespace App;

class AlipayAdapter implements PayAdapter{

    private $alipay;

    public function __construct(Alipay $alipay) {
        $this->alipay = $alipay;
    }

    public function pay($amount) {
        $this->alipay->sendPayment($amount);
    }
}

Wxpay

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
<?php
namespace App;

class Wxpay
{
    public function __construct() {
        // ...
    }

    public function doPayment($amount) {
        echo "微信支付: ". $amount;
    }
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
<?php
namespace App;

class WxpayAdapter implements PayAdapter{

    private $wxpay;

    public function __construct(Wxpay $wxpay) {
        $this->wxpay = $wxpay;
    }

    public function pay($amount) {
        $this->wxpay->doPayment($amount);
    }
}

CashPay

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
<?php
namespace App;

class CashPay
{
    public function __construct() {
        // ...
    }

    public function pay($amount) {
        echo "现金支付: ". $amount;
    }
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
<?php
namespace App;

class CashPayAdapter implements PayAdapter{

    private $cash;

    public function __construct(CashPay $cash) {
        $this->cash = $cash;
    }

    public function pay($amount) {
        $this->cash->pay($amount);
    }
}

客户端调用

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
<?php
namespace App;

class Client {

    public function alipay(){
        $alipay = new AlipayAdapter(new Alipay());
        $alipay->pay(100);
    }

    public function wxpay(){
        $alipay = new WxpayAdapter(new Wxpay());
        $alipay->pay(100);
    }

    public function cash(){
        $alipay = new CashPayAdapter(new CashPay());
        $alipay->pay(100);
    }

}

简单解释一下,当我们做一些调用第三方API时会用到对方提供的SDK,而对方的SDK有时会有改动,比如支付宝支付的接口中付款的方法以前叫sendPayment,后来又改成sendPay,如果我们不使用上面的适配器模式的话,如果系统中有多处调用支付类需要改动很多,而使用适配模式后只需要更改AlipayAdapter里的pay方法即可,不需要暴露其外部接口,而且在增加新的支付平台时只需增加对应的Adapter适配类做转化即可。

适配器模式使用场景还是非常多的,比如数据库操作类的封装、缓存类的封装、日志类的封装都可以使用适配器模式,另外像我们做旅游电商平台的经常需要对接美团、携程、有赞、飞猪、去哪儿等OTA平台,这些平台的接口有的更新比较频繁,而且部分平台提供的SDK里命名也比较混乱,不能做到平滑升级,如果一开始就使用适配器模式去对接,后续不管怎么改都只需要改对接的适配器类,业务代码一行也不需要更改。

参考资料

觉得本文对你有用请点右下角“再看”,也欢迎转发,如对文中观点有不同看法欢迎评论留言。