手続きを意識させない設計をする
Twitter のツイート数を取得できる URL がある。
http://urls.api.twitter.com/1/urls/count.json?url=example.org
例えば、この URL からツイート数をコンソールに表示するプログラムを書きたいとする。coffeescript で
愚直に書くとこんな感じ
JSON_URL = "http://urls.api.twitter.com/1/urls/count.json?url=" request = require "request" request JSON_URL+"example.org", (err, res, body) -> data = JSON.parse body console.log data.count
これだと使いまわせないから、関数にする。
getTweetCount = (url, callback) -> request JSON_URL+url, (err, res, body) -> data = JSON.parse body callback data.count getTweetCount "example.org", (count) -> console.log count
良さ気に見える。
でも、これだと、複数回よんだとき、
同じ URL でも何度も読みに行ってしまうから、良くない。
getTweetCount "example.org", (count) -> console.log "first", count getTweetCount "example.org", (count) -> console.log "second", count
もちろん、これぐらい近い位置で呼ぶなら、
同じコールバックで括ればいいけど、そうも行かないことは、ままある。
ここで満を持して、クラスやイベントを活用する。
予め、load をしておいて、値を取得するときは、 get を使う
EventEmitter = (require "eventemitter2").EventEmitter2 class TweetCount extends EventEmitter constructor: (@url) -> load: => request JSON_URL+@url, @onLoad onLoad: (err, res, body) => data = JSON.parse body @count = data.count @emit "load" get: -> @count tweetCount = new TweetCount "example.org" tweetCount.load() tweetCount.on "load", -> console.log "first", tweetCount.get() tweetCount.on "load", -> console.log "second", tweetCount.get()
しかし、これだと、
load 前と load 後で、値の呼び方を変えなければいけない。
load 後は .on "load" が呼ばれないし、load 前は @count が定義されていない。
使うときには、TweetCount が既にロードされているかどうかを、常に意識しなければいけない。
そういう事のないように、
複雑な手続きを踏むインターフェイスは、
順番や状態を意識せずに使えるよう、善く設計する必要がある。
class TweetCount extends EventEmitter constructor: (@url) -> @loaded = false @loading = false get: (callback) => return callback @count if @loaded @once "load", callback @load() unless @loading load: => @loading = true request JSON_URL+@url, @onLoad onLoad: (err, res, body) => data = JSON.parse body @count = data.count @loading = false @loaded = true @emit "load", @count tweetCount = new TweetCount "example.org" tweetCount.get (count) -> console.log "first", count tweetCount.get (count) -> console.log "second", count
状態を吸収することで、
常に同じインターフェイスを利用できるように、設計をする。