业务场景:我们每天需要准时到公司上班下班,可以搭乘不同交通工具。
在不使用设计模式时,通常可以这样写:
//通勤
class Commute{
//上班
public function gotowork(){
switch ($way) {
case 'bus':
return '乘坐巴士上班';
default:
return '乘坐地铁上班';
}
}
//下班
public function gohome(){
switch ($way) {
case 'bus':
return '乘坐巴士下班';
default:
return '乘坐地铁下班';
}
}
}
以后需要新增通勤方式、修改某种通勤方式,都需要修改Commute类,此类的维护随着业务增加变得复杂。
由此引入工厂模式:
不管使用简单工厂模式还是依赖注入,我们首先需要定义交通工具。
1.定义交通工具接口、类
//交通工具
interface Vehicle{
function travel();
}
//巴士
class Bus implements Vehicle{
public function travel(){
return "巴士";
}
}
//地铁
class Metro implements Vehicle{
public function travel(){
return "地铁";
}
}
2.一个生产乘坐不同交通方式的工厂
//普通工厂模式
class Factory{
//通勤方案:根据交通方式返回不同的对象
public function mychoice($way){
switch ($way) {
case 'bus':
return new Bus;
default:
return new Metro;
}
}
}
3.调用工厂类实现出行
class Commute{
//此时我上班通勤方式只需修改传入Factory的参数即可更改
public function gotowork(){
return '乘坐'.(new Factory)->mychoice('bus')->travel().'上班</br>';
}
public function gohome(){
return '乘坐'.(new Factory)->mychoice('bus')->travel().'下班</br>';
}
}
Commute只需关注要乘坐bus上班,不关心bus具体实现。
echo (new Commute)->gotowork();
引入工厂模式后,新增、修改都给了工厂,用户出行变得简洁。
但是新增、修改仍然需要修改工厂类,此时引入依赖注入。
以上步骤1定义交通工具接口、类仍然有用,第2步之后变为:
//通勤
class Commute{
private $way;
//Vehicle的意思是定义强类型:在此处的参数$car必须是遵从Vehicle契约的对象实例。如果这里参数类型强制是一个类的话,代表的是参数必须是类的实例或者是该类子类的实例
public function __construct(Vehicle $car){
$this->way = $car;
}
//此时我上班通勤方式只需修改传入Factory的参数即可更改
public function gotowork(){
return '乘坐'.$this->way->travel().'上班</br>';
}
public function gohome(){
return '乘坐'.$this->way->travel().'下班</br>';
}
}
Commute不再关心具体交通工具,只关心自己要乘坐交通工具上班,在调用时传入交通工具bus:
echo (new Commute(new Bus))->gotowork();
依赖注入解决了对工厂类的解耦,但是当后期需要更换增加新的交通方式,交通工具类依然需要修改、增加,此时可以引入IOC容器。
IOC容器
以laravel为例,它的服务容器本身是一个类,在程序执行前用户可以通过匿名函数将自己的依赖关系绑定到容器,等程序真正运行时,容器可以通过反射,递归地解析当前类的依赖、它的依赖的依赖并加载到容器中运行,简而言之,容器是可以注册各种接口并实现绑定的空间。这样做是为了最大程度地对依赖关系解耦。
在laravel中,这个依赖关系写在\config\app.php中,它通常获取的是.env文件中的配置参数。
反射是非常重要的概念,很多语言都有,在我看来它有一些旁观者的感觉,抓来一个类、对象都可以对其分析、构建,而不用真的引用它、运行它才可以。
有说法是反射会带来性能的一定损失,我没有测试过无法下定论,不过对于laravel这样的框架来说,优雅才是第一位的,它首先要提高的是开发效率,要让代码更加整洁、扩展性更强。
https://www.php.net/manual/zh/book.reflection.php
https://learnku.com/docs/laravel-core-concept/5.5/依赖注入,控制翻转,反射/3017 |