Slide 1

Slide 1 text

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

Slide 2

Slide 2 text

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

Slide 3

Slide 3 text

ユーザーからのメッセージをどう処理するか 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);

Slide 4

Slide 4 text

ユーザーからのメッセージをどう処理するか 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);

Slide 5

Slide 5 text

問題点 • Controllerですべてを扱う感じになってつらい • でも、できるだけ運用しやすくしたい • コードを読みやすくする • 会話のパターンを増やしやすくする

Slide 6

Slide 6 text

Command デザインパターン • ある目的を達成するための一連の処理群(前後処理、 設定、実行)をひとつのオブジェクトにまとめて外 部化し、マクロを呼び出す感覚で使えるようにする 仕組み • 複雑な一連の処理群をオブジェクトとしてカプセル 化し、切り出したもの • 登場人物 • Invoker • Command • Receiver : コマンドをキューイング、実行 : 処理対象のメソッドを手順通り実行 : 処理対象

Slide 7

Slide 7 text

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

Slide 8

Slide 8 text

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

Slide 9

Slide 9 text

アルバイトアプリ版の構成と設計 MessageController どのCommandを 実行するか管理する Commandを実行する HogeCommand メッセージの送信 メッセージ受信時の処理 FugaCommand メッセージの送信 メッセージ受信時の処理 User Invoker Command Receiver

Slide 10

Slide 10 text

悩みどころ 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();

Slide 11

Slide 11 text

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

Slide 12

Slide 12 text

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

Slide 13

Slide 13 text

悩みどころ 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(); 別のところにある……

Slide 14

Slide 14 text

たとえば • メッセージ判別メソッド • メッセージの受信~次のメッセージの送信 をまとめてみる class ReceiveGender: CommandMessage { class func init(user) { this.user = user; } func receiveAnswer(answer) { user.gender = answer; bot.pushMessage(user, ‘You are student?’); } }

Slide 15

Slide 15 text

たとえば 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

Slide 16

Slide 16 text

この場合 • 配列とクラスを追加すれば応答パターンを増やせる • 返答に応じて次の質問が変わる場合の処理が Controllerからいなくなる。処理が多いときは良い • フロー的にはわかりづらくなった気がする • 質問と回答が同じクラスにない AskGender 性別を聞くときの処理 性別が送られたときの処理 Start 性別を聞くときの処理 ReceiveGender 性別が送られたときの処理 学生かどうか聞くときの処理

Slide 17

Slide 17 text

まとめ • フルスクラッチで作ろうとすると、設計が難しい • それでもこのパターンを使えば少しはましになると 思うので、よければ使ってみてください • フレームワークとかもあるので、 そういうのを使うのも良いと思います