账号密码登录
微信安全登录
微信扫描二维码登录

登录后绑定QQ、微信即可实现信息互通

手机验证码登录
找回密码返回
邮箱找回 手机找回
注册账号返回
其他登录方式
分享
  • 收藏
    X
    laravel 容器,支付模块设计
    35
    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模型是变化的。

    0
    打赏
    收藏
    点击回答
        全部回答
    • 0
    • 几缕清葭 普通会员 1楼
      502 Bad Gateway

      502 Bad Gateway


      nginx
    更多回答
    扫一扫访问手机版
    • 回到顶部
    • 回到顶部