假设我现在需要做一个支付服务,那么我先设计一个接口 interface PayInterface{ public function pay(Order $order) : string;} 然后实现这个接口 class WeiXinPay implements PayInterface{ public function pay(Order $or
假设我现在需要做一个支付服务,那么我先设计一个接口
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); }
这样看起来也可以,但是我困扰了
- 我没有办法简单的替换支付方式了 (WeixinPay 替换成 AliPay)
- 调用方手动的去new 相关的实现,产生了严重的依赖。
我希望能够:
- 能够简单的替换支付方式(服务提供者)
- 调用方只需要 调用 pay(Order $order) 方法即可完成支付,即使我切换支付对于调用方来说都是不需要改变的,符合里氏替换规则