从Websocket服务器中删除Switch语句气味

时间:2015-12-18 00:50:10

标签: php json refactoring ratchet

我不确定这个问题是否属于这里,因为它是“有争议的”,但让我们试一试。

在阅读了很多关于它的例子和问题(比如 this one 之后,看起来非常相似),我仍然无法弄清楚是否应该选择多态来替换开关。

这是一个Ratchet WebSocket服务器,它接收JSON消息并根据消息type执行例程:

public function onMessage(ConnectionInterface $from, $msg) {
    /*!
    Triggers everytime a message is received by the application.
    Depending on @p $msg type, the application will broadcast @p $msg accordingly.

    @param ConnectionInterface $from 
    This is the socket (client) who sent @p $msg.
    @param string $msg
    A JSON string sent by the client.
    */
    $usermsg = json_decode($msg, true);
    if (isset($usermsg["message"])) {
        $actual_msg = $this->removeHTML($usermsg["message"]);
    }

    switch ($usermsg["type"]) {

        case 'text':
            $this->text($from, $actual_msg, "text");
            break;

        case 'token':
            $this->token($from, $usermsg["im"]);
            break;

        case "ready":
            $this->ready($from);
            break;

        case "action":
            $this->text($from, $actual_msg, "action");
            break;

        case "users":
            $this->whoIsOnline($from);
            break;

        case "listen":
            $this->listen($from);
            break;

        case "end":
            $this->finish($from, $actual_msg);
            break;

        case 'statInit':
            $this->statInit($from);
            break;
    }
}

事情是,$msg是一个字符串,因为它是JSON,没有任何对象被实例化为任何到达的消息。这就是没有类层次结构的原因,因为消息不是对象。实际上,除了实际的服务器之外没有其他类。

在任何情况下,这是唯一存在于服务器端的交换机(客户端中有另一个交换机,但它是jQuery所以它是一个不同的故事),所以添加新功能应该是添加一个案例和一个方法,而不是那很难。该项目不会增长太多,但我希望它能够轻松扩展。

我应该坚持使用OOP设计并为每个到达的消息创建一个对象并应用多态?自服务器处理聊天消息以来,似乎有点压倒性。

1 个答案:

答案 0 :(得分:1)

一方面,在一天结束时,这对您有用,并且相对容易维护。完全的OOP可能只是纯粹和/或自我的练习。

如果您将OOP方法提升到下一级别,如果是我,我将创建一个SocketMessage类,在构造函数中接受JSON消息字符串。我还将为每个扩展它的消息类型创建一个SocketHandler类,其中包含各个处理程序类。关于你的方法之后的一些粗略代码是:

public function onMessage(ConnectionInterface $from, $json) 
{
    $message = new SocketMessage($json);
    return $message->dispatch();
}

dispatch()调用将成为SocketMessage类的一部分,并根据消息类型确定将其指向哪个处理程序。它会知道哪些处理程序可用,因为您将首先使用基类SocketHandler类注册它们。

// Somewhere that you initialize code
SocketHandler::register('text', Handlers\TextHandler::class);
SocketHandler::register('token', Handlers\TokenHandler::class);
SocketHandler::register('ready', Handlers\ReadyHandler::class);

注册处理程序只会将它们放在类中的静态数组中,以便稍后访问。在SocketMessage::dispatch()函数内部,您可能会执行以下操作:

class SocketMessage
{
    ...
    public function __construct($json)
    {
        // Parse raw message data
        $this->message = @json_decode($json, true);
        if (empty($this->message)) {
           throw new Exception('SocketMessage expects a valid JSON string.');
        }
    }
    ...
    public function dispatch()
    {
        $type = $this->message['type'];
        $handler = SocketHandler::get($type);

        return $handler->handle($this->message);
    }
    ...
} 

我不太确定我要把这一切都放在哪里。我的主要观点是,您可以使其更加面向对象,这将使其更具灵活性和可扩展性,但这也会带来更多可维护性方面的困难。这真的是一个偏好和项目范围的问题(即它是一个由很多人维护的大型项目,还是你在业余时间玩的业余爱好剧本?)