热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Laravel深入学习6应用体系结构:解耦事件处理器

声明:本文并非博主原创,而是来自对《Laravel4FromApprenticetoArtisan》阅读的翻译和理解,当然也不是原汁原味的翻译,能保证90%的原汁性,另外因为是理解

声明:本文并非博主原创,而是来自对《Laravel 4 From Apprentice to Artisan》阅读的翻译和理解,当然也不是原汁原味的翻译,能保证90%的原汁性,另外因为是理解翻译,肯定会有错误的地方,欢迎指正。

欢迎转载,转载请注明出处,谢谢!

应用体系结构:解耦事件处理器

介绍

现在我们已经介绍了很多使用Laravel 4构建健壮应用的特性,下面来深入挖掘更多的细节。本章我们将讨论诸如队列、事件这些众多事件处理器的解耦,也包括类似“类事件”结构的路由过滤。

别堵塞了传输层

大多数“事件处理器”被当作_传输层_组件。换言之,队列处理、事件触发器、或者一个外来请求都被用来调用某些调用处理。要像处理控制器一样处理这些事件处理器,并避免在其中涉及太多业务逻辑。

解耦事件处理器

开始本命题前,我们来使用一个示例。假想下把队列处理器用来发送SMS消息给用户。在发送消息之后,处理器讲发送了的消息记录成历史以便我们知道有哪些用户收到了这些消息。代码实现如下:

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();
}
}

仅测试这块代码,就可能遇到一些问题。首先,测试困难。Twilio_SMS类是在fire方法中实例化的,这意味着我们无法使用注入的方式模拟服务。其次,在处理器中我们直接用到了Eloquent模型,这就给测试带来了另外一个问题,我们必须在方法中进行真正的数据库访问。最后,我们在队列之外无法进行SMS消息发送。我们的SMS消息发送逻辑完全糅合在Laravel队列中了。

通过将逻辑提取到某一“服务”中的方法,我们可以将应用中的SMS消息发送逻辑从Laravel的队列服务中解耦出来。从而可以在应用中的任何地方发送消息。当我们进行了这种解耦处理,这种重构也是我们的代码变得更加具有可测性。

让我们来修改下代码:

class User extends Eloquent {
/**
* Send the User an SMS message
*
* @param SmsCourierInterface $courier
* @param string $message
* @return SmsMessage
*/
public function sendSmsMessage(SmsCourierInterface $courier, $message)
{
$courier->sendMessage($this->phone_number, $message);
return $this->sms()->create(array(
'to'=> $this->phone_number,
'message'=> $message,
));
}
}

在这个重构的代码实例中,我们将发送消息的逻辑提取到User模型中。同时向该方法中注入SmsCourierInterface接口实现逻辑,使我们更好的测试逻辑中的方方面面。重构了短信发送逻辑之后,再对队列进行重构:

class SendSMS {
public function __construct(UserRepository $users, SmsCourierInterface $courier)
{
$this->users = $users;
$this->courier = $courier;
}
public function fire($job, $data)
{
$user = $this->users->find($data['user']['id']);
$user->sendSmsMessage($this->courier, $data['message']);
$job->delete();
}
}

在重构的示例中,可以看到,队列服务已经足够轻量。它在队列和我们_真正的_应用逻辑之间已经足够符合_传输层_这个概念。赞!这意味着我们可以在队列之外轻易的发送消息。最后,让我们编写一些测试代码:

class SmsTest extends PHPUnit_Framework_TestCase {
public function testUserCanBeSentSmsMessages()
{
/**
* Arrage ...
*/
$user = Mockery::mock('User[sms]');
$relation = Mockery::mock('StdClass');
$courier = Mockery::mock('SmsCourierInterface');
$user->shouldReceive('sms')->once()->andReturn($relation);
$relation->shouldReceive('create')->once()->with(array(
'to' => '555-555-5555',
'message' => 'Test',
));
$courier->shouldReceive('sendMessage')->once()->with(
'555-555-5555', 'Test'
);
/**
* Act ...
*/
$user->sms_number = '555-555-5555';
$user->sendMessage($courier, 'Test');
}
}

其他事件处理器

我们可以改进很多这种类型的“事件处理器”。将他们限定为简单的“传输层”来使用,能将复杂的业务逻辑很好的组织和解耦到框架之外。为了巩固下这种思想,下面我们举例一个路由过滤器,用它来验证用户是否为我们的“高级”订阅用户。

Route::filter('premium', function()
{
return Auth::user() && Auth::user()->plan == 'premium';
});

乍看像是没什么问题。这么小的代码能有啥问题呢?然而,在这么小的过滤中,也能意识到我们将应用的实现细节暴漏了出来。注意,我们在过滤中进行对plan属性进行了检测。“级别”的检测逻辑层紧紧的揉进了路由、传输层。如果我们将“高级”订阅用户的套餐存放到数据库或者用户模型中,这里又必须对我们的路由过滤器进行修改!

相应的,做些小的改编:

Route::filter('premium', function()
{
return Auth::user() && Auth::user()->isPremium();
});

这样小的改编带来的效果是明显的,付出的代价也是小的。通过在模型中对用户是否属于高级订阅用户的判断,我们将路由中的检测逻辑解耦了出来。我们的过滤程序不在负责检测用户订阅级别的职责。相应的,它只需简单的询问用户模型即可。现在,如果订阅级别的判断存放在数据库中,路由过滤不需要更改任何代码!

该谁负责?

我们又一次讨论了_职责_的概念。牢记,一个类应有的职责是什么,和他涉及的范围是明确的。尽量避免在事件处理器中掺杂太多的业务逻辑。


推荐阅读
  • 云原生应用最佳开发实践之十二原则(12factor)
    目录简介一、基准代码二、依赖三、配置四、后端配置五、构建、发布、运行六、进程七、端口绑定八、并发九、易处理十、开发与线上环境等价十一、日志十二、进程管理当 ... [详细]
  • 基于layUI的图片上传前预览功能的2种实现方式
    本文介绍了基于layUI的图片上传前预览功能的两种实现方式:一种是使用blob+FileReader,另一种是使用layUI自带的参数。通过选择文件后点击文件名,在页面中间弹窗内预览图片。其中,layUI自带的参数实现了图片预览功能。该功能依赖于layUI的上传模块,并使用了blob和FileReader来读取本地文件并获取图像的base64编码。点击文件名时会执行See()函数。摘要长度为169字。 ... [详细]
  • 云原生边缘计算之KubeEdge简介及功能特点
    本文介绍了云原生边缘计算中的KubeEdge系统,该系统是一个开源系统,用于将容器化应用程序编排功能扩展到Edge的主机。它基于Kubernetes构建,并为网络应用程序提供基础架构支持。同时,KubeEdge具有离线模式、基于Kubernetes的节点、群集、应用程序和设备管理、资源优化等特点。此外,KubeEdge还支持跨平台工作,在私有、公共和混合云中都可以运行。同时,KubeEdge还提供数据管理和数据分析管道引擎的支持。最后,本文还介绍了KubeEdge系统生成证书的方法。 ... [详细]
  • [译]技术公司十年经验的职场生涯回顾
    本文是一位在技术公司工作十年的职场人士对自己职业生涯的总结回顾。她的职业规划与众不同,令人深思又有趣。其中涉及到的内容有机器学习、创新创业以及引用了女性主义者在TED演讲中的部分讲义。文章表达了对职业生涯的愿望和希望,认为人类有能力不断改善自己。 ... [详细]
  • 使用在线工具jsonschema2pojo根据json生成java对象
    本文介绍了使用在线工具jsonschema2pojo根据json生成java对象的方法。通过该工具,用户只需将json字符串复制到输入框中,即可自动将其转换成java对象。该工具还能解析列表式的json数据,并将嵌套在内层的对象也解析出来。本文以请求github的api为例,展示了使用该工具的步骤和效果。 ... [详细]
  • 图解redis的持久化存储机制RDB和AOF的原理和优缺点
    本文通过图解的方式介绍了redis的持久化存储机制RDB和AOF的原理和优缺点。RDB是将redis内存中的数据保存为快照文件,恢复速度较快但不支持拉链式快照。AOF是将操作日志保存到磁盘,实时存储数据但恢复速度较慢。文章详细分析了两种机制的优缺点,帮助读者更好地理解redis的持久化存储策略。 ... [详细]
  • 计算机存储系统的层次结构及其优势
    本文介绍了计算机存储系统的层次结构,包括高速缓存、主存储器和辅助存储器三个层次。通过分层存储数据可以提高程序的执行效率。计算机存储系统的层次结构将各种不同存储容量、存取速度和价格的存储器有机组合成整体,形成可寻址存储空间比主存储器空间大得多的存储整体。由于辅助存储器容量大、价格低,使得整体存储系统的平均价格降低。同时,高速缓存的存取速度可以和CPU的工作速度相匹配,进一步提高程序执行效率。 ... [详细]
  • 不同优化算法的比较分析及实验验证
    本文介绍了神经网络优化中常用的优化方法,包括学习率调整和梯度估计修正,并通过实验验证了不同优化算法的效果。实验结果表明,Adam算法在综合考虑学习率调整和梯度估计修正方面表现较好。该研究对于优化神经网络的训练过程具有指导意义。 ... [详细]
  • flowable工作流 流程变量_信也科技工作流平台的技术实践
    1背景随着公司业务发展及内部业务流程诉求的增长,目前信息化系统不能够很好满足期望,主要体现如下:目前OA流程引擎无法满足企业特定业务流程需求,且移动端体 ... [详细]
  • 从壹开始前后端分离【 .NET Core2.0 +Vue2.0 】框架之六 || API项目整体搭建 6.1 仓储模式
    代码已上传Github+Gitee,文末有地址  书接上文:前几回文章中,我们花了三天的时间简单了解了下接口文档Swagger框架,已经完全解放了我们的以前的Word说明文档,并且可以在线进行调 ... [详细]
  • Git GitHub多人协作
    在学校做一个小项目需要多人协作,就用到了gitHub,百度了一下多数写得乱七八糟或者支离破碎,于是总结了一下自己的步骤如下,第一次使用GitHUb,哪里不对望大神指出一.前期准备: ... [详细]
  • 广度优先遍历(BFS)算法的概述、代码实现和应用
    本文介绍了广度优先遍历(BFS)算法的概述、邻接矩阵和邻接表的代码实现,并讨论了BFS在求解最短路径或最短步数问题上的应用。以LeetCode中的934.最短的桥为例,详细阐述了BFS的具体思路和代码实现。最后,推荐了一些相关的BFS算法题目供大家练习。 ... [详细]
  • 快速搭建SSM(Spring,SpringMVC,Mybatis)环境详细过程我是做移动(Android)开发的,这几天利用项目空隙大概学 ... [详细]
  • 2.ElasticSearch练习索引 : sms-logs-index类型:sms-logs-type   数据导入部分PUTsms_logs_indexsms_logs_typ ... [详细]
  • 使用人|方开源_通过SCCM数据库获取计算机硬件报告
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了通过SCCM数据库获取计算机硬件报告相关的知识,希望对你有一定的参考价值。需求 ... [详细]
author-avatar
梅花七
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有