💎一站式轻松地调用各大LLM模型接口,支持GPT4、智谱、豆包、星火、月之暗面及文生图、文生视频 广告
# 依赖注入与依赖倒置 依赖注入 > 依赖注入关键:接口、多态、构造函数注入 将一个对象传入另一个对象中(将对象以new时的构造函数或者方法传入另一个类保存) 常规的想在注册完成后发送一个邮件的写法 ``` <pre class="calibre10">``` <span class="token">//1 Email.class.php发送邮件的类 </span> class <span class="token4">Mail</span><span class="token3">{</span> public <span class="token5">function</span> <span class="token4">send</span><span class="token3">(</span><span class="token3">)</span><span class="token3">{</span> <span class="token">//发送邮件的具体代码 </span> <span class="token3">}</span> <span class="token3">}</span> <span class="token">//2底层代码: 由注册的类'Register.clas10s.php' 里调用send()发送</span> class <span class="token4">Register</span><span class="token3">{</span> private $_emailObject<span class="token3">;</span> public <span class="token5">function</span> <span class="token4">doRegister</span><span class="token3">(</span><span class="token3">)</span><span class="token3">{</span> <span class="token">//这里是如何注册</span> $this<span class="token1">-</span><span class="token1">></span>$_emailObject <span class="token1">=</span> <span class="token5">new</span> <span class="token4">Mail</span><span class="token3">(</span><span class="token3">)</span><span class="token3">;</span><span class="token">//对象 </span> $this<span class="token1">-</span><span class="token1">></span>$_emailObject<span class="token1">-</span><span class="token1">></span><span class="token4">send</span><span class="token3">(</span><span class="token3">)</span><span class="token3">;</span><span class="token">//发送邮件(连续调用) </span> <span class="token3">}</span> <span class="token3">}</span> <span class="token">//3上层代码: 某个注册页面: </span> include <span class="token2">'Mail.class.php'</span><span class="token3">;</span> include <span class="token2">'Register.class.php'</span><span class="token3">;</span> $reg <span class="token1">=</span> <span class="token5">new</span> <span class="token4">Register</span><span class="token3">(</span><span class="token3">)</span><span class="token3">;</span> $reg<span class="token1">-</span><span class="token1">></span><span class="token4">doRegister</span><span class="token3">(</span><span class="token3">)</span><span class="token3">;</span> ``` ``` xxx天过后,产品人员说发送邮件的不好,要使用发送短信的,然后你说这简单我把'Mail'类改下 然后你必须将底层代码Register类的doRegister()里的内容`new Mail()`修改为`new Message()` 怎么解决了'Register'对信息发送类的依赖呢? 利用接口的多态性 使用构造函数注入的方法,使得它只依赖于发送短信的接口,只要实现其接口中的'send'方法,不管你怎么发送都可以(除了构造函数注入,还有方法注入及属性注入 ) ``` <pre class="calibre10">``` <span class="token">//修改后</span> <span class="token">//1 Mail.class.php各种方式发送消息的类</span> interface <span class="token4">Mail</span><span class="token3">{</span> public <span class="token5">function</span> <span class="token4">send</span><span class="token3">(</span><span class="token3">)</span><span class="token3">;</span><span class="token">//接口类的方法全是公共public 的抽象方法 子类必须全部继承接口的父类</span> <span class="token3">}</span> class <span class="token4">Email</span> implements <span class="token4">Mail</span><span class="token3">{</span> public <span class="token5">function</span> <span class="token4">send</span><span class="token3">(</span><span class="token3">)</span><span class="token3">{</span> <span class="token">//发送email</span> <span class="token3">}</span> <span class="token3">}</span> class <span class="token4">SmsMail</span> implements <span class="token4">Mail</span><span class="token3">{</span> public <span class="token5">function</span> <span class="token4">send</span><span class="token3">(</span><span class="token3">)</span><span class="token3">{</span> <span class="token">//发送短信</span> <span class="token3">}</span> <span class="token3">}</span> <span class="token">//2然后又注册后又要发送消息的类'Register.class.php'</span> class <span class="token4">Register</span><span class="token3">{</span> private $_mailObj<span class="token3">;</span> public <span class="token5">function</span> <span class="token4">__construct</span><span class="token3">(</span>Mail $mailObj<span class="token3">)</span><span class="token3">{</span> $this<span class="token1">-</span><span class="token1">></span>_mailObj<span class="token1">=</span>$mailObj<span class="token3">;</span><span class="token">//初始化发送方式</span> <span class="token3">}</span> public <span class="token5">function</span> <span class="token4">doRegister</span><span class="token3">(</span><span class="token3">)</span><span class="token3">{</span> $this<span class="token1">-</span><span class="token1">></span>_mailObj<span class="token1">-</span><span class="token1">></span><span class="token4">send</span><span class="token3">(</span><span class="token3">)</span><span class="token3">;</span><span class="token">//发送消息</span> <span class="token3">}</span> <span class="token3">}</span> <span class="token">//3 注册页面</span> <span class="token5">function</span> <span class="token4">run</span><span class="token3">(</span><span class="token3">)</span><span class="token3">{</span> $reg <span class="token1">=</span> <span class="token5">new</span> <span class="token4">Register</span><span class="token3">(</span><span class="token3">)</span><span class="token3">;</span><span class="token">//实例化注册类</span> $emailObj <span class="token1">=</span> <span class="token5">new</span> <span class="token4">Email</span><span class="token3">(</span><span class="token3">)</span><span class="token3">;</span> $smsMail <span class="token1">=</span> <span class="token5">new</span> <span class="token4">SmsMail</span><span class="token3">(</span><span class="token3">)</span><span class="token3">;</span> $reg<span class="token1">-</span><span class="token1">></span><span class="token4">doRegister</span><span class="token3">(</span>$emailObj<span class="token3">)</span><span class="token3">;</span><span class="token">//用email发送</span> $res<span class="token1">-</span><span class="token1">></span><span class="token4">doRegister</span><span class="token3">(</span>$smsMail<span class="token3">)</span><span class="token3">;</span><span class="token">//用短信发送</span> <span class="token3">}</span> <span class="token4">run</span><span class="token3">(</span><span class="token3">)</span><span class="token3">;</span> <span class="token">//较好的封装</span> class <span class="token4">Client</span><span class="token3">{</span> public static <span class="token5">function</span> <span class="token4">main</span><span class="token3">(</span><span class="token3">)</span><span class="token3">{</span> $mother <span class="token1">=</span> <span class="token5">new</span> <span class="token4">Register</span><span class="token3">(</span><span class="token3">)</span><span class="token3">;</span> $emailObj <span class="token1">=</span> <span class="token5">new</span> <span class="token4">Email</span><span class="token3">(</span><span class="token3">)</span><span class="token3">;</span> $smsMail <span class="token1">=</span> <span class="token5">new</span> <span class="token4">SmsMail</span><span class="token3">(</span><span class="token3">)</span><span class="token3">;</span> $mother<span class="token1">-</span><span class="token1">></span><span class="token4">narrate</span><span class="token3">(</span>emailObj<span class="token3">)</span><span class="token3">;</span> $mother<span class="token1">-</span><span class="token1">></span><span class="token4">narrate</span><span class="token3">(</span>smsMail<span class="token3">)</span><span class="token3">;</span> <span class="token3">}</span> <span class="token3">}</span> $client <span class="token1">=</span> <span class="token5">new</span> <span class="token4">Client</span><span class="token3">(</span><span class="token3">)</span><span class="token3">;</span> $client<span class="token1">-</span><span class="token1">></span><span class="token4">main</span><span class="token3">(</span><span class="token3">)</span><span class="token3">;</span> ``` ``` 上面的代码解决了'Register'对信息发送类的依赖,使用构造函数注入的方法,使得它只依赖于发送短信的接口,只要实现其接口中的'send'方法, 注意在这里上面的必须先引入信息发送类在引入注册类 怎么解决引入加载顺序呢,这就需要用到依赖倒置啦,上面例子很好的实现了该思想,实例化注册类Register的时候加上了类型限制,如果传入的是信息发送类则实例化成功否则会报错 **依赖倒置原则**(`Dependence Inversion Principle``DIP`)思想的定义是“**高层模块不应该依赖低层模块,二者都应该依赖其抽象;抽象不应该依赖细节;细节应该依赖抽象** 传统软件设计中,上层代码依赖于下层代码,当下层出现变动时, 上层代码也要相应变化,维护成本较高。而DIP的核心思想是上层定义接口,下层实现这个接口, 从而使得下层依赖于上层,降低耦合度,提高整个系统的弹性。这是一种经实践证明的有效策略。 依赖注入的目的是**为了提升组件重用的频率** 推荐一篇博文:[依赖注入和控制反转的理解,写的太好了](https://blog.csdn.net/liunianqingshi/article/details/78144489)