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

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) 方法即可完成支付,即使我切换支付对于调用方来说都是不需要改变的,符合里氏替换规则

laravel 依赖注入 接口设计的更多相关文章

  1. laravel依赖注入 容器

    [看完就懂]Laravel 服务容器,IoC,DI      DI DI就是常说的依赖注入,那么究竟什么是依赖注入呢? 打个比方,电脑(非笔记本哈)需要键盘和鼠标我们才能进行操作,这个‘需要’换句话说 ...

  2. ASP.NET Core 6框架揭秘实例演示[06]:依赖注入框架设计细节

    由于依赖注入具有举足轻重的作用,所以<ASP.NET Core 6框架揭秘>的绝大部分章节都会涉及这一主题.本书第3章对.NET原生的依赖注入框架的设计和实现进行了系统的介绍,其中设计一些 ...

  3. Laravel 依赖注入原理

    众所周知 Laravel 的文档对于依赖注入只写了如何使用,相信大多数人对于他的实现原理并不太清楚.虽然使用过程中并不需要关心她的原理,但是了解原理让你使用起来更自信.这个帖子就通过一个小 demo ...

  4. php+laravel依赖注入浅析

    laravel容器包含控制反转和依赖注入,使用起来就是,先把对象bind好,需要时可以直接使用make来取就好. 通常我们的调用如下. $config = $container->make('c ...

  5. laravel依赖注入浅析

    laravel容器包含控制反转和依赖注入,使用起来就是,先把对象bind好,需要时可以直接使用make来取就好. 通常我们的调用如下. $config = $container->make('c ...

  6. laravel 依赖注入

    <?php interface Animal{ public function attack(); public function talk(); } class People implemen ...

  7. 5. Effective Java 第三版——使用依赖注入取代硬连接资源

    Tips <Effective Java, Third Edition>一书英文版已经出版,这本书的第二版想必很多人都读过,号称Java四大名著之一,不过第二版2009年出版,到现在已经将 ...

  8. Effective Java 第三版——5. 使用依赖注入取代硬连接资源

    Tips <Effective Java, Third Edition>一书英文版已经出版,这本书的第二版想必很多人都读过,号称Java四大名著之一,不过第二版2009年出版,到现在已经将 ...

  9. DotNetCore依赖注入实现批量注入

    文章转载自平娃子(QQ:273206491):http://os.pingwazi.cn/resource/batchinjectservice 一.依赖注入 通过依赖注入,可以实现接口与实现类的松耦 ...

随机推荐

  1. Ranger开源贡献统计

    统计一下自己在Ranger开源社区贡献的Issue数量, 开源社区的Issue主要分为New Feature,Bug,Improvement, 这三种都是和代码相关的,会直接修改开源项目的代码库, 还 ...

  2. Shell调试Debug的三种方式

    Shell脚本进行Debug调试的三种方法如下: 1.在调用脚本的时候开启deubg sh -x shell.sh 2.在脚本文件首行开启deubg #!/bin/bash -x 3. 使用set开启 ...

  3. PHP 中的闭包函数和匿名函数

    闭包函数 闭包函数通常作为函数中的函数使用. <?php $foo = function($s) { echo $s; }; $foo('hello'); <?php function t ...

  4. 为什么要避免在 Go 中使用 ioutil.ReadAll?

    原文链接: 为什么要避免在 Go 中使用 ioutil.ReadAll? ioutil.ReadAll 主要的作用是从一个 io.Reader 中读取所有数据,直到结尾. 在 GitHub 上搜索 i ...

  5. 使用 spring security 中的BcryptPasswordEncoder对象对用户密码进行加密

    一.引入security启动器 在子工程中直接引入,不用指定版本号 二.在启动类中把BCryptPasswordEncoder对象注入到容器中 三.在service 层注入 四. 调用encode方法 ...

  6. 基于CentOS7.x gitlab环境搭建,卸载,汉化 --卸载篇

    gitlab环境搭建,卸载,汉化 --卸载篇 完全卸载 停止gitlab gitlab-ctl stop 卸载gitlab rpm -e gitlab-ce 查看gitlab进程  ps aux | ...

  7. CentOS 7 连接不到网络解决方法(设置静态ip)

    使用VM12创建虚拟机并安装CentOS 7,但是安装完成后发现连接不到网络. ping jd.com发现不通 因为在创建虚拟机的时候 我们选择的是NAT模式 这里给出NAT模式下对应的的解决方法: ...

  8. Go语言系列- Socket编程和Redis

    Socket编程 一.socket编程概述 什么是socket编程? socket编程是计算机PC机器上2个程序通过一个双向的通信连接实现数据的交互,这个连接的一端就是一个socket.socket的 ...

  9. Go语言命名规范

    一.变量命名规范 变量命名一般采用驼峰式,当遇到特有名词(缩写或简称,如DNS)的时候,特有名词根据是否私有全部大写或小写.例子: var apiClient var URLString 二.常量命名 ...

  10. Go语言读取各种配置文件

    配置文件结构体 config.go package config type System struct { Mode string `mapstructure:"mode" jso ...