Save 37% off PRO during our Black Friday Sale! »

アルバイト LINE BOT で使った「コマンドパターン」の紹介

Cfd6a7b025c390205d1dd8765230bca1?s=47 kiwi
February 07, 2018

アルバイト LINE BOT で使った「コマンドパターン」の紹介

社内LT大会で登壇した際の資料です。

Cfd6a7b025c390205d1dd8765230bca1?s=128

kiwi

February 07, 2018
Tweet

Transcript

  1. kiwi @koga_wiwi NIFTY Corporation アルバイト LINE BOT で使った 「コマンドパターン」の紹介 2017/10/4

  2. アルバイト LINE BOTについて 対話型バイト診断 シフト時間通知 バイトみくじ

  3. ユーザーからのメッセージをどう処理するか switch message.text { } case ‘Hello’: message.user.friendPoint += 1;

    bot.replyMessage(‘Hello, my friend!’); case ‘Find Arbeit’: res = Arbeit.find(message.text); bot.replyMessage(res.title, res.link);
  4. ユーザーからのメッセージをどう処理するか switch message.text { } case ‘Hello’: message.user.friendPoint += 1;

    bot.replyMessage(‘Hello, my friend!’); case ‘Find Arbeit’: res = Arbeit.find(message.text); bot.replyMessage(res.title, res.link); bot.buttonMessage(‘Find More’); case ‘Find More’: res = Arbeit.find(message.text).skip(1); bot.replyMessage(res.title, res.link);
  5. 問題点 • Controllerですべてを扱う感じになってつらい • でも、できるだけ運用しやすくしたい • コードを読みやすくする • 会話のパターンを増やしやすくする

  6. Command デザインパターン • ある目的を達成するための一連の処理群(前後処理、 設定、実行)をひとつのオブジェクトにまとめて外 部化し、マクロを呼び出す感覚で使えるようにする 仕組み • 複雑な一連の処理群をオブジェクトとしてカプセル 化し、切り出したもの

    • 登場人物 • Invoker • Command • Receiver : コマンドをキューイング、実行 : 処理対象のメソッドを手順通り実行 : 処理対象
  7. LINE BOT バイト探しの場合(擬似コード) protocol CommandMessage { func init(user); func postQuestion();

    // 質問するとき func receiveAnswer(answer); // 回答を受け取ったとき } class AskGender: CommandMessage { func init(user) { this.user = user; } func postQuestion() { bot.pushMessage(user, ‘Whats your gender?’); } func receiveAnswer(answer) { user.gender = answer; } }
  8. LINE BOT バイト探しの場合(擬似コード) class MessageController { func receive(request) { message

    = Message.from(request) commandForReceived = null; commandForPost = null; switch message.type { case MessageTypeStart: commandForPost = AskGender(message.user); case MessageTypeGender: commandForReceived = AskGender(message.user); commandForPost = AskStudent(message.user); } commandForReceived?.receiveAnswer(message); commandForPost?.postQuestion();
  9. アルバイトアプリ版の構成と設計 MessageController どのCommandを 実行するか管理する Commandを実行する HogeCommand メッセージの送信 メッセージ受信時の処理 FugaCommand メッセージの送信

    メッセージ受信時の処理 User Invoker Command Receiver
  10. 悩みどころ class MessageController { func receive(request) { message = Message.from(request)

    commandForReceived = null; commandForPost = null; switch message.type { case MessageTypeStart: commandForPost = AskGender(message.user); case MessageTypeGender: commandForReceived = AskGender(message.user); commandForPost = AskStudent(message.user); } commandForReceived?.receiveAnswer(message); commandForPost?.postQuestion();
  11. 受け取ったメッセージをどのコマンドに処理させるか • メッセージテキストを正規表現で切り出したり • 特定のメッセージパターンだったり • ユーザーの状態から判断したり

  12. 受け取ったメッセージをどのコマンドに処理させるか • メッセージテキストを正規表現で切り出したり • 特定のメッセージパターンだったり • ユーザーの状態から判断したり するけど、その判別はどこで……?

  13. 悩みどころ class MessageController { func receive(request) { message = Message.from(request)

    commandForReceived = null; commandForPost = null; switch message.type { case MessageTypeStart: commandForPost = AskGender(message.user); case MessageTypeGender: commandForReceived = AskGender(message.user); commandForPost = AskStudent(message.user); } commandForReceived?.receiveAnswer(message); commandForPost?.postQuestion(); 別のところにある……
  14. たとえば • メッセージ判別メソッド • メッセージの受信~次のメッセージの送信 をまとめてみる class ReceiveGender: CommandMessage {

    class func init(user) { this.user = user; } func receiveAnswer(answer) { user.gender = answer; bot.pushMessage(user, ‘You are student?’); } }
  15. たとえば class MessageController { let mesToCmd: [((Message -> bool), class)]

    = [ ]; func receive(message) { user = message.user; command = null; for tuple in mesToCmd { if tuple[0](message) { command = tuple[1]; break; } } command?.receiveAnswer(); ({mes in return mes.text == ‘Start’}, AskGender.class), ({mes in return mes.data == ‘Gender’}, ReceiveGender.cl
  16. この場合 • 配列とクラスを追加すれば応答パターンを増やせる • 返答に応じて次の質問が変わる場合の処理が Controllerからいなくなる。処理が多いときは良い • フロー的にはわかりづらくなった気がする • 質問と回答が同じクラスにない

    AskGender 性別を聞くときの処理 性別が送られたときの処理 Start 性別を聞くときの処理 ReceiveGender 性別が送られたときの処理 学生かどうか聞くときの処理
  17. まとめ • フルスクラッチで作ろうとすると、設計が難しい • それでもこのパターンを使えば少しはましになると 思うので、よければ使ってみてください • フレームワークとかもあるので、 そういうのを使うのも良いと思います