Laravel : 使用动作类整理你的代码(翻译)

2018-06-05  本文已影响0人  阪本先生

友偶阅网文一篇,头中尾英,阅不能,遂中译之。原文链接 :Keeping your Laravel applications DRY with single action classes

“这段代码该放在哪里?”恐怕是在谈论应用结构时最经常提起的问题。“我应该放在 Controller 里吗?还是 Model ?还是哪里?”,虽然 Laravel 是个十分灵活的框架,但要解答这个问题也不总能简单明了。

当你知道你的应用程序只有一个接入点的时候,把逻辑写在 Controller 是完全没问题的。但如今应用一般都会有好几个接入点共用同一个功能。

例如,很多应用都会有一个用户注册的表单,提交到 Controller ,然后根据是否成功注册来返回有用的信息。在移动端应用的场景下,一般都会有个使用 JSON 格式返回的 API 专门用于用户注册。而且利用 Laravel 的 artisan 命令来创建用户也很常见,尤其是在项目前期的开发阶段。

这些重复代码的确看上去没什么毛病,但如果就这样让业务逻辑继续扩充下去,例如:你希望给新注册用户发一封提醒邮件,那么你需要在两个 Controller 里同时加上这个逻辑。所以为了代码能够整洁优雅起来,我们需要把它放到其他地方去。

别把服务类神化了

一开始,可以先临时创建一个类,把所有针对某个业务逻辑的代码整理起来,例如:

这样看上去就好多了;我们可以直接从 Controller 里调用 User 的 create()/ delete() ,通过任意途径返回结果。然而这方式有个问题:我们处理业务逻辑的时候很少使用一种模式

例如我们有这个业务逻辑:当用户创建账号的时候,需要创建一篇新的博客。如果我们继续使用刚才的模式,我们需要创建 BlogService 然后使其作为依赖注入到 UserService 中:

很显然,当我们的应用变得越来越大,会有越来越多的服务类,有些还依赖了 5 个甚至 6 个其他的服务类,代码像被猫玩过的毛线球剪不断理还乱 —— 我们无论如何都要避免这种结局。

引入动作类

如果我们不使用里面塞了几个方法的单一服务类,而是把逻辑切分到好几个类里面呢?我在最近的好几个工程里都使用了这种模式,结果十分不错。

首先,我们暂时先把“服务”这个抽象而且模糊的术语丢掉,然后引入“动作”类,并且赋予以下定义:

创建 CreateUser 动作

现在,让我们用 CreateUser 动作类来重构刚才的例子。

你可能觉得奇怪,为什么代码要在 Email 存在的情况下抛出异常,这个不应该是在请求的时候就应该验证一次吗?当然应该让验证器去做这件事,不过,强制动作类遵循业务逻辑是一个好主意。这样做不但能够让业务逻辑更明确(不用过多考虑异常情况),也更容易调试。

下面是我们使用动作类重构后的控制器:

现在我们再也不用在注册流程更改的时候同时修改两边的代码,干净整洁。

内嵌动作

当我们需要往应用里倒入 1000 个用户的时候,我们可以写一个依赖 CreateUser 的动作类:

干净整洁,简单易懂。在这里我们在 Collection::map() 里重用了 CreateUser ,返回一个集合,装着新鲜出炉的用户们。我们可以稍作优化:当有重复邮件的时候,我们可以通过返回 Null 对象,或者往 Logger 里丢 INFO ,随你喜欢。

装饰一下 Actions

现在,假设我们要往日志里记录每一个用户的注册。我们可以直接把代码放到动作自身上,但我们也可以使用装饰器模式

然后,使用 Laravel 的 IoC 容器,我们可以把 LogCreateUser 类绑在 Createuser 类上,这样当我们就总能在需要后者的时候把原型注入进去:

这样做甚至更容易地通过环境变量或者配置控制日志的开启和关闭:

总结

使用这种模式大概会在开始先产生一大堆的类。当然,为了减少一下文章篇幅读起来比较方便,这里只举了这个简单的用户注册例子。当复杂度增加的时候,这个模式的价值就开始体现出来了 — — 因为你清楚这些边界清楚分工明确的代码在哪。

使用动作类的好处:

而且,这些实践都是基于我最近这些年使用 Laravel 的经验以及我写过的项目总结出来的。它们对我来说非常管用,以至于我甚至在中小型项目里使用。

我非常希望能够与你一同交流分享,如果你有不同的实践方式那就最好不过了!

上一篇下一篇

猜你喜欢

热点阅读