假設我如今須要作一個支付服務,那麼我先設計一個接口html
interface PayInterface{ public function pay(Order $order) : string; }
而後實現這個接口數據庫
class WeiXinPay implements PayInterface{ public function pay(Order $order) :string{ //具體實現 } }
開始發現一個問題
微信支付是須要三個關鍵參數的 (appID , appSecret , key)
我就接着修改代碼,我但願這三個參數是經過外部注入的,而不是寫死在WeiXinPay裏面,因而乎我就修改了WeiXinPay的構造函數,並新增了一個接口與實現json
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); }
沒有問題,一切都如預期同樣。(將來我也能夠很容置的將微信支付換成支付寶,只須要在服務提供者切換實現便可)app
過了兩天,又有一個新的需求了。終極問題來了,老闆但願每一次支付的時候收款人都不同,也就是說微信支付的appId,appSecret,appKey每次都不同dom
我開始修改個人代碼,我想着:我讓這些有變更的參數經過構造函數的方式傳遞進來總能夠吧。函數
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); }
這樣看起來也能夠,可是我困擾了測試
我但願可以:微信支付