zoukankan      html  css  js  c++  java
  • laravel 依赖注入 接口设计

     

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

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

    然后实现这个接口

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

    开始发现一个问题
    微信支付是需要三个关键参数的 (appID , appSecret , key)
    我就接着修改代码,我希望这三个参数是通过外部注入的,而不是写死在WeiXinPay里面,于是乎我就修改了WeiXinPay的构造函数,并新增了一个接口与实现

    interface PaySettingsInterface {
        public function getSettings() : array;
    }
    
    class WeixinPaySettings implements PaySettingsInterface{
        public function getSettings() : array{
            return [
                'app_id' => 'xxxx',
                'app_secret' => 'yyyyy',
                'key' => 'zzzz'
            ];
        }
    }
    
    class WeiXinPay implements PayInterface{
    
        protected $settings;
        public __construct(PaySettingsInterface $settings){
            $this->settings = $settings->getSettings();
        }
    
        public function pay(Order $order) :string{
            //具体实现
        }
    }

    好了。感觉到这里这个PayInterface的实现应该是没问题了。我开始写服务提供者

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

    写一段测试代码来跑跑看

        public function testPay(){
            $orderSn = Strings::randomString('NUMBER+',12);
            $order = factory(Order::class)->make([
                'sn' => $orderSn,
                'uid' => 111,
                'to_uid' => 109,
                'relation_user' => json_encode([109,108,107,104,102,12]),
                'amount' => 1,
                'attach' => 1,
                'status' => Constans::ORDER_NO_PAY,
                'is_settle' => Constans::NO_SETTLE,
            ]);
            
            /**
             * @var $service PayInterface
            */
            $service = $this->app->make(PayInterface::class);
            
            $res = $service->pay($order);
            $this->assertIsString($res);
        }

    没有问题,一切都如预期一样。(未来我也可以很容置的将微信支付换成支付宝,只需要在服务提供者切换实现即可)

    过了两天,又有一个新的需求了。终极问题来了,老板希望每一次支付的时候收款人都不一样,也就是说微信支付的appId,appSecret,appKey每次都不一样

    我开始修改我的代码,我想着:我让这些有变动的参数通过构造函数的方式传递进来总可以吧。

    interface PaySettingsInterface {
        public function getSettings() : array;
    }
    
    class WeixinPaySettings implements PaySettingsInterface{
        protected $appID;
        protected $appKey;
        protected $appSecret;
    
        public function __construct($appID ,$appKey ,$appSecret){
            $this->appID = $appID;
            $this->appKey = $appKey;
            $this->appSecret = $appSecret;
        }
    
        public function getSettings() : array{
            return [
                'app_id' => $this->appID,
                'app_secret' => $this->appSecret,
                'key' => $this->appKey
            ];
        }
    }
    
    class WeiXinPay implements PayInterface{
    
        protected $settings;
        public __construct(PaySettingsInterface $settings){
            $this->settings = $settings->getSettings();
        }
    
        public function pay(Order $order) :string{
            //具体实现
        }
    }
    
    //然后我修改我的服务提供者
    $this->app->bind(PaySettingsInterface::class,function($app){
        //怎么new 呢? 老板的需求是可能每次都不同,这些数据又可能来自数据库,也可能来自缓存。
        $instance = new WeixinPaySettings(???);
        return $instance;
    });
    $this->app->bind(PayInterface::class , WeiXinPay::class);
    //到这里,看来是无法通过容器自动注入PaySettingsInterface的实现了。那么我就只能这样了。在测试代码中:
    
    public function testPay(){
        $orderSn = Strings::randomString('NUMBER+',12);
        $order = factory(Order::class)->make([
            'sn' => $orderSn,
            'uid' => 111,
            'to_uid' => 109,
            'relation_user' => json_encode([109,108,107,104,102,12]),
            'amount' => 1,
            'attach' => 1,
            'status' => Constans::ORDER_NO_PAY,
            'is_settle' => Constans::NO_SETTLE,
        ]);
        
        //查询数据库得到settings
        $settings = Db::get();
        $paySettings  = new WeixinPaySettings($settings['app_id'],$settings['app_secret'],$settings['app_key']);
        
        $payService = new WeixinPay($paySettings);
        
        $res = $payService->pay($order);
        $this->assertIsString($res);
    }

    这样看起来也可以,但是我困扰了

    1. 我没有办法简单的替换支付方式了 (WeixinPay 替换成 AliPay)
    2. 调用方手动的去new 相关的实现,产生了严重的依赖。

    我希望能够:

    1. 能够简单的替换支付方式(服务提供者)
    2. 调用方只需要 调用 pay(Order $order) 方法即可完成支付,即使我切换支付对于调用方来说都是不需要改变的,符合里氏替换规则
  • 相关阅读:
    出现System.web.mvc冲突的原因及解决方法CS0433
    看完此文还不懂NB-IoT,你就过来掐死我吧...
    html5调用手机陀螺仪实现方向辨识
    黑盒测试和白盒测试的区别
    CentOS7 下 keepalived 的安装和配置
    centos 下 mysql+keepalived实现双主自由切换
    MySQL 高可用性—keepalived+mysql双主(有详细步骤和全部配置项解释)
    备份VMware虚拟磁盘文件 移植到其他虚拟机
    Centos7 Mysql 双机热备实现数据库高可用
    CentOS7配置Mysql热备份
  • 原文地址:https://www.cnblogs.com/guiyishanren/p/11152770.html
Copyright © 2011-2022 走看看