laravel 容器,支付模块设计

发布于 2022-09-11 18:23:44 字数 4265 浏览 14 评论 0

假设我现在需要做一个支付服务,那么我先设计一个接口

interface PayInterface{
    public function pay(Order $order) : string;
}

然后实现这个接口

class WeiXinPay implements PayInterface{
    protected $appID = "xxxx";
    protected $mchID = "xxxx";
    protected $mchKey = "xxxx";

    public function pay(Order $order) :string{
        //具体实现
    }
}

然后在PayServiceProvider中注册这个服务

$this->app->bind(PayInterface::class , WeiXinPay::class);

写个单元测试试试

public function testPay(){
        $orderSn = Strings::randomString('NUMBER+',12);
        $order = factory(Order::class)->make([
            'sn' => $orderSn,
            'amount' => 1,
            'attach' => 1,
        ]);
        
        /**
         * @var $service PayInterface
        */
        $service = $this->app->make(PayInterface::class);
        
        $res = $service->pay($order);
        $this->assertIsString($res);
    }

这里看上去没有问题,一切都如预期一样。
但是很快需求就变了,WeiXinPay的三个属性appID,mchID,mchKey不能写死,需要从外部读取。我便开始改造我的代码。
如何优雅的得到WeiXinPay依赖的三个参数呢? 我想到了再定义一个接口,这样:

interface PaySettingsInterface {
    public function getSettings() : array;
}

然后实现他

//从env文件读取
class EnvPaySettings implements PaySettingsInterface{
    public function getSettings() : array{
        return [
            'app_id' => 'xxxx',
            'app_secret' => 'yyyyy',
            'key' => 'zzzz'
        ];
    }
}

//从数据库读取
class DataBasePaySettings implements PaySettingsInterface{
    public function getSettings() : array{
        $settings = DB::table('pay_settings')->get();
        return $settings;
    }
}

修改我的WeiXinPay

class WeiXinPay implements PayInterface{

    protected $settings;

    public __construct(PaySettingsInterface $settings){
        $this->settings = $settings->getSettings();
    }

    public function pay(Order $order) :string{
        //具体实现
    }
}

修改PayServiceProvider

//这一行我可以方便的随时修改EnvPaySetting为DataBasePaySettings
$this->app->bind(PaySettingsInterface::class,EnvPaySettings::class);
$this->app->bind(PayInterface::class , WeiXinPay::class);

再跑我的单元测试

public function testPay(){
        $orderSn = Strings::randomString('NUMBER+',12);
        $order = factory(Order::class)->make([
            'sn' => $orderSn,
            'amount' => 1,
            'attach' => 1,
        ]);
        
        /**
         * @var $service PayInterface
        */
        $service = $this->app->make(PayInterface::class);
        
        $res = $service->pay($order);
        $this->assertIsString($res);
    }

一切还是没变,都如预期一样,我的单元测试代码一行都没有改。
但是,又有新的需求出现了,老板说,支付的时候要每个收款人的mchID,appID,appKey都不一样。
于是我开始改我的代码,第一个思路是再写一个UserPaySettings,说干就干

class User extends Model{
    //model 的其它定义

    public function settings(){
       $settings = //获取settings的代码
       return $settings;
    }
}


//从用户关联读取
class UserPaySettings implements PaySettingsInterface{
    protected $user;
    public function __construct(User $user){
       $this->user = $user;
    }

    public function getSettings() : array{
        $settings = $this->user->settings();
        return $settings;
    }
}

好了。我天真的再去修改我的PayServiceProvider,把之前的EnvPaySettings替换成UserPaySettings

$this->app->bind(PaySettingsInterface::class,UserPaySettings::class);
$this->app->bind(PayInterface::class , WeiXinPay::class);

再天真的跑一下我的单元测试,还是一行代码都没改

public function testPay(){
        $orderSn = Strings::randomString('NUMBER+',12);
        $order = factory(Order::class)->make([
            'sn' => $orderSn,
            'amount' => 1,
            'attach' => 1,
        ]);
       
        /**
         * @var $service PayInterface
        */
        $service = $this->app->make(PayInterface::class);
        
        $res = $service->pay($order);
        $this->assertIsString($res);
    }

然后就报错了。因为UserPaySettings是要注入一个User模型的
怎么办,通过容器貌似已经无法再自动注入了,因为传递进去的User模型是变化的。

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

不一样的天空 2022-09-18 18:23:44
$this->app->bind(PaySettingsInterface::class, function () {
    return new UserPaySettings(User::find(rand(1, 5))->get());
});
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文