Menu

46.重构

本节说明

  • 对应视频教程第 46 小节:Refactoring For Better or Worse

本节内容

本节我们来对上一节的内容进行一些重构。首选看一下我们要重构的部分:
forum\app\Thread.php

    .
    .
    public function addReply($reply)
    {
        $reply = $this->replies()->create($reply);

        // Prepare notifications for all subscribers
        $this->subscriptions
            ->filter (function ($sub) use ($reply){
                return $sub->user_id != $reply->user_id;
            })
            ->each
            ->notify($reply);

        return $reply;
    }
    .
    .

我们使用filter函数过滤回复自己创建的话题的通知,但是我们可以更简单一点:

    .
    .
    public function addReply($reply)
    {
        $reply = $this->replies()->create($reply);

        // Prepare notifications for all subscribers
        $this->subscriptions
            ->where('user_id','!=',$reply->user_id)
            ->each
            ->notify($reply);

        return $reply;
    }
    .
    .

运行一下全部的功能测试:
file
虽然我们的功能测试通过,但是你仔细思考一下上面的代码就会发现:我们的添加回复和发送消息的代码耦合在一起。这非常不利于后期维护跟功能重构,所以我们要进行解耦。我们将利用 Laravel 的事件系统 来进行解耦:

事件机制是一种很好的应用解耦方式,因为一个事件可以拥有多个互不依赖的监听器。例如,如果你希望每次订单发货时向用户发送一个 Slack 通知。你可以简单地发起一个 OrderShipped 事件,让监听器接收之后转化成一个 Slack 通知,这样你就可以不用把订单的业务代码跟 Slack 通知的代码耦合在一起了。

Laravel 应用中的 EventServiceProvider 有个 listen 数组包含所有的事件(键)以及事件对应的监听器(值)来注册所有的事件监听器,可以灵活地根据需求来添加事件。现在,让我们增加一个 ThreadHasNewReply 事件:
forum\app\Providers\EventServiceProvider.php

    .
    .
    protected $listen = [
        'App\Events\ThreadHasNewReply' => [
            'App\Listeners\NotifyThreadSubscribers',
        ],
    ];
    .
    .

我们再使用event:generate命令为事件和监听器创建文件:

$ php artisan event:generate

接着修改我们新创建的两个文件内容为以下:
forum\app\Events\ThreadHasNewReply.php

<?php

namespace App\Events;

use Illuminate\Queue\SerializesModels;

class ThreadHasNewReply
{
    use SerializesModels;
    public $thread;
    public $reply;

    /**
     * Create a new event instance.
     *
     * @param \App\Thread $thread
     * @param \App\Reply $reply
     */
    public function __construct($thread,$reply)
    {
        //
        $this->thread = $thread;
        $this->reply = $reply;
    }
}

forum\app\Listeners\NotifyThreadSubscribers.php

<?php

namespace App\Listeners;

use App\Events\ThreadHasNewReply;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue;

class NotifyThreadSubscribers
{
    /**
     * Handle the event.
     *
     * @param  ThreadHasNewReply  $event
     * @return void
     */
    public function handle(ThreadHasNewReply $event)
    {
        // Prepare notifications for all subscribers

        $event->thread->subscriptions
            ->where('user_id','!=',$event->reply->user_id)
            ->each
            ->notify($event->reply);
    }
}

接下来我们改为用事件来触发通知:
forum\app\Thread.php

<?php

namespace App;

use App\Events\ThreadHasNewReply;
.
.
class Thread extends Model
{
    .
    .
    public function addReply($reply)
    {
        $reply = $this->replies()->create($reply);

        event(new ThreadHasNewReply($this,$reply));

        return $reply;
    }
    .
    .
}

再次测试:
file
看上去很酷,是不是?但是,我们在重构的时候,需要思考我们是否真的有必要进行这样的重构。在我们当前的情形中,消息通知的动作我们可以很简单地抽取成一个独立的方法就能满足我们的需求。也就是说,在当前我们并不需要用到事件系统。我们将新建的两个文件删除,并添加我们需要的方法:
forum\app\Thread.php

    .
    .
    public function addReply($reply)
    {
        $reply = $this->replies()->create($reply);

        $this->notifySubscribers($reply);

        return $reply;
    }

    public function notifySubscribers($reply)
    {
        $this->subscriptions
            ->where('user_id','!=',$reply->user_id)
            ->each
            ->notify($reply);
    }
    .
    .

再次测试:
file
本节我们学的是,不要为了重构而重构。Good Luck!

本文章首发在 Laravel China 社区
上一篇 下一篇
讨论数量: 0
发起讨论


暂无话题~
刻意练习,每日精进。
3
点赞
145
浏览
0
讨论

维护者
14
14