[ask-tips] Classを使って文脈に応じたYesIntentのハンドラー実装を楽にする

何かの処理をしたい場合、「そのインテントが呼ばれたとき」と「文脈ではいという返事がきた場合」の2つを処理する必要があります。そして従来の書き方では、以下のように実際の処理をするhandlerのcanHandleでif文を […]

広告ここから
広告ここまで

目次

    何かの処理をしたい場合、「そのインテントが呼ばれたとき」と「文脈ではいという返事がきた場合」の2つを処理する必要があります。そして従来の書き方では、以下のように実際の処理をするhandlerのcanHandleでif文を重ねるやり方でした。

      canHandle (handlerInput) {
        if (
          canHandle(handlerInput, 'IntentRequest', 'SetReminderIntent') ||
          canHandle(handlerInput, 'IntentRequest', 'AMAZON.YesIntent')
        ) {
          const { state } = handlerInput.attributesManager.getSessionAttributes()
          return state === STATE.SET_REMINDER
        }
        return false
      }

    これでも特に問題はないのですが、できるならばもっと見通しをよくしたいなと思います。

    クラスを使う

    そこでhandlerをクラス化する方法を提案したいと思います。

    例えば以下のようなデータを保存するハンドラークラスを作ります。

    
    
    class SaveTownName implements RequestHandler {
      canHandle(handlerInput: HandlerInput) {
        return isMatchedIntent(handlerInput, 'SaveTownName')
      }
      async handle(handlerInput: HandlerInput) {
        let town = getSessionAttribute(handlerInput, 'town')
        if (!town) {
          town = getSlot(handlerInput, 'town')
        }
        await handlerInput.attributesManager.setPersistentAttributes({
          persistedTownName: town
        })
        await handlerInput.attributesManager.savePersistentAttributes()
    
        const speechText = '町名を保存しました。次回から町名を省略してゴミの日を確認することができます。'
        return handlerInput.responseBuilder
          .speak(speechText)
          .withSimpleCard(SKILL_NAME, speechText)
          .getResponse()
      }
    }
    
    export default SaveTownName

    そしてYesIntentからも利用したい場合、以下のような継承クラスを作ります。

    import SaveTownName from '../SaveUserData/SaveTownName'
    
    class YesSaveTownIntent extends SaveTownName {
      canHandle(handlerInput: HandlerInput) {
        if (!isYesIntent(handlerInput)) return false
        const state = getSessionAttribute(handlerInput, 'nextAction')
        return state === 'saveTownName'
      }
    }
    
    export default new YesSaveTownIntent()

    こうすることで、例えばYesIntentのみを1フォルダにまとめて見通しをよくするということが可能になります。

    また、両方のファイルが1つのインテントのみサポートする形になりますので、あとで実装を確認する際にも見通しがかなりよくなります。

    クラスを使うときの注意点

    注意したいことは、「newでインスタンスを初期化した状態でしかhandlerとして登録できない」ということです。ですのでYesIntentのサンプルでは、初期化したものをexportするように実装されています。

    継承元はexport時に初期化することができませんので、登録する際に初期化するようにしましょう。

    return Ask.SkillBuilders.standard()
            .addRequestHandlers(
                    new SaveTownName(),
                    YesSaveTownIntent,
            )

    広告ここから
    広告ここまで
    Home
    Search
    Bookmark