laravel <学徒到工匠> 总结

<学徒到工匠> 总结
让你学会写出一个解耦,可测试的大型web软件
学会应用架构,目录布局,代码分层,超越mvc三层思维,另外还学会单元测试
围绕设计模式五大原则 每一个原则都有反例和优化后的案例
原文: https://laravelacademy.org/category/road-to-artisan

契约 接口

纲领

要始终牢记「无知是福」。我们不想让类知道依赖是如何工作的,只需要知道它们能做什么。所以,先定义好契约,再来写控制器
接口即纲领:接口有助于开发应用所提供的、已定义好的功能「框架」。 在组件的设计阶段,团队里使用接口进行讨论是很方便的,例如,定义一个 BillingNotifierInterface 接口,然后讨论它提供哪些方法。在编写任何实现代码前,最好先通过接口讨论达成一致,这是构建一套好 API 的必要前提!

在大型应用中,接口是很有帮助的。和提升的代码灵活性、可测试性相比,多敲几下键盘花费的时间就显得微不足道了。当你在不同的接口实现类之间切换如飞的时候,你的经理一定会被你的神速惊到。此外,你也能够写出更能适应变化的代码。https://laravelacademy.org/post/9701.html

绑定依赖

通过匿名函数绑定

我们在定义绑定关系的时候可以用匿名函数,这样做的好处是用到该依赖时才会实例化,从而提升了应用的性能。

$this->app->bind(BillingNotifierInterface::class, function ($app) {
   return new EmailBillingNotifier();
});

通过类名字符串

$this->app->bind(BillerInterface::class, StripeBiller::class);
这种方式会在绑定时就会实例化 StripeBiller,性能不及匿名函数。

单例

在绑定实现到接口时,你也可以使用 singleton 方法,这样容器在整个请求生命周期中只会实例化这个实现类一次,从而实现单例模式:

$this->app->singleton(BillerInterface::class, StripeBiller::class);

在绑定接口实现类时使用 bind 还是 singleton 方法可以这样来考虑:如果在一次请求生命周期中该类只需要有一个实例,就使用 singleton;否则就使用 bind。

提示

不要被条条框框束缚。记住,服务提供者并不只是扩展包才能使用。请尽情使用它来组织管理你的应用服务。

分层

核心思想就是分层
你可能已经注意到,优化应用目录结构的关键就是对不同组件的责任进行划分,或者说为不同的职责创建不同的层。控制器只负责接收和响应 HTTP 请求,然后调用合适的业务逻辑层的类。
你的业务逻辑/领域逻辑层才是应用最核心的部分,其中包含了读取数据,验证数据,执行支付,发送电子邮件,还有程序里所有其他功能的代码。
事实上,你的领域逻辑层不需要知道任何关于「Web」的事情!Web 层仅仅是一种访问应用程序的传输机制,关于 Web 和 HTTP 请求的一切不应该超出路由和控制器层的范围。做出好的架构设计的确很有挑战性,但好的架构设计也会带来可维护的、更加清晰的代码。

应用架构篇-不可测试的类

首先,我们看一个不好的例子。假设有一个队列处理器用来给用户发送手机短信。信息发送后,处理器会记录消息日志以便保存给用户发送过的所有消息历史。对应代码如下:

class SendSMS
{
    public function fire($job, $data)
    {
        $twilio = new Twilio_SMS($apiKey);
        $twilio->sendTextMessage(array(
            'to'=> $data['user']['phone_number'],
            'message'=> $data['message'],
        ));
        $user = User::find($data['user']['id']);
        $user->messages()->create(array(
            'to'=> $data['user']['phone_number'],
            'message'=> $data['message'],
        ));
        $job->delete();
    }
}

简单审查下这个类,你可能会发现一些问题。首先,它难以测试。在 fire 方法里直接实例化了 Twilio_SMS 类,意味着我们没法注入一个模拟的服务。其次,我们直接在处理器中使用了 Eloquent 模型,导致在测试时肯定会对数据库造成影响。最后,我们没法在队列以外发送短信。所有短信发送逻辑和 Laravel 队列耦合在一起了。

插件自动注册功能

Laravel 5.5 开始增加了一个新的功能 「Package Auto Discovery」。这个功能使得 Laravel 能更容易地对包进行安装和启用的管理。

包的开发者可以在 composer.json 文件中添加一个新的部分,用来告诉框架应该注册哪些服务提供器或者它们的外观。

"extra": { "laravel": { "providers": [ "Barryvdh\Debugbar\ServiceProvider" ] } }

提交插件

只要在 Github 项目中关联了Packagist 服务,就可以在 Packagist 后台「submit」该插件 默认是dev-master版本,我们需要打 tag设置版本号

如果你还为在哪里存放注册代码发愁,服务提供者是个不错的地方。

我们之前就讲过,使用服务提供者来管理框架扩展代码是一个非常不错的方式,将相应代码放到服务提供者的 boot 方法即可。

查看配置的providers

学院君注:由于 Laravel 5.5 中新增了包自动发现功能,所以 config/app.php 配置文件的 providers 数组提供的服务服务者列表并不全,最全的列表在 bootstrap/cache/services.php 的 providers 数组中。

五大原则

开放封闭原则

要小心那些泄露实现细节的依赖。当一个依赖的实现需要改变时,不应该要求它的调用者做任何修改。如果需要调用者进行修改的话,往往意味着该依赖「泄露」了实现的细节。当你的抽象泄露时,开放封闭原则就不管用了。

里氏替换原则

通俗点说就是个:如果一个类使用了某个接口的实现,那么一定可以通过该接口的其它实现来替换它,不用做出任何修改。

里氏替换原则规定对象可以被其子类的实例所替换,并且不会影响到程序的正确性。

一个类所具备的「周边」知识,例如外围代码和依赖,会帮助这个类完成它的工作。当你想要构建一个健壮的大型应用时,限制类的知识会是一个反复出现、非常重要的主题。

还要注意如果不遵守里氏替换原则,那么可能会影响到我们之前已经讨论过的其他原则。不遵守里氏替换原则,那么开放封闭原则一定也会被打破。因为,如果调用者必须检查实例属于哪个子类,则一旦有了新的子类,调用者就得做出改变。

你可能已经注意到这个原则和前面提到的「泄露抽象实现细节」密切相关。数据库仓库类的实现细节泄露就是里氏替换原则被破坏的第一迹象。所以要时刻留意那些泄露!

接口隔离原则

所有五个「SOLID」原则都是相关的,也就是说违背了其中一个原则,通常意味着也违背了其他的原则。当你违背了接口隔离原则,肯定也违背了单一职责原则。

与其保有一个包含不是所有实现都需要的方法的「臃肿」接口,不如将其拆分成多个更细粒度的接口,然后各自按需独立实现。这样将臃肿接口拆分成细粒度、功能集中的接口后,调用方也可以依赖更小的接口,而不必为我们不需要的功能买单。

依赖反转原则

这个原则的另一层意思是,抽象接口不应该依赖具体实现,但具体实现应该依赖抽象接口。

下面是一个反例:

class Authenticator {

    public function __construct(DatabaseConnection $db)
    {
        $this->db = $db;
    }

    public function findUser($id)
    {
        return $this->db->exec('select * from users where id = ?', array($id));
    }

    public function authenticate($credentials)
    {
        // Authenticate the user...
    }
}

你可能猜到了,Authenticator 是用来查找和认证用户的。我们来看一下它的构造函数,你会发现它使用了类型提示,要求传入一个DatabaseConnection 对象,所以该认证器和数据库被紧密地耦合在一起,并且用户数据只能通过支持 SQL 的关系型数据库提供。此外,我们的高层次代码(Authenticator)直接依赖低层次代码(DatabaseConnection)。

什么是[高层次代码]和[低层次代码]

低层次代码用于实现一些底层的基本操作,比如从磁盘读文件、操作数据库等。
高层次代码用于封装复杂的业务逻辑并且依靠低层次代码来实现功能,但不能直接和低层次代码耦合在一起。
换句话说,高层次代码需要依赖低层次代码的顶层抽象,比如接口。不仅如此,低层次代码也应当依赖抽象接口。

反转的思想:

使用这一原则会反转很多开发者设计应用的方式。不再将高层次代码直接和低层次代码以「自上而下」的方式耦合在一起,这个原则规定不论高层级还是低层次代码都要依赖于一个它的高层次的抽象,从而使得低层次代码依赖于高层次代码的需求抽象。

依赖关系链已经被反转了,代码变得更灵活,可以更好的拥抱变化!

最后

一个类依赖另一个类,每一个小功能都是抽象为一个接口,层层依赖
laravel 可以很好的解决依赖关系

转载于:https://my.oschina.net/yiupng/blog/3029105

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值