##概要
TwitterAPIを利用してTwitterに投稿する機能を作って欲しいという要望があったので、Scalaで実現してみました。
後々、コンテキストは変えずにヨコ展開して欲しいといった(例えばFacebookで投稿したいといった)要望が出てくると思われるので、今回はStrategyパターンを利用しました。
StrategyパターンってのはGoFデザインパターンの1つですな。
##設計に関して
■やり取り
ディレクター「〜の条件で、Twitterに投稿する機能を実装してほしい」
私「なるほど。では、今後、〜の条件でFacebookに投稿するといったことも考えられますか?」
ディレクター「そうしてくれたら嬉しい。まずTwitterに投稿することを実現してほしい」
■Strategyパターンを選んだ経緯
「〜の条件で」(Context)ってのは固定らしい。
今回はTwitterに投稿するという戦略(Strategy)を実装すればよいが、
別の戦略(予測できる戦略は「Facebookに投稿する」という戦略)に切り替えられ、
また併用できるような設計にした方が望ましいだろう。
戦略はTwitterやFacebookといったソーシャルメディアに投稿する戦略。
抽象化するならソーシャルメディアに限定するのもよろしくないので、インターフェースを「外部メディア」としよう。
では、実装に移ろう。(※業務ロジックは省いてます)
###1.Strategy(戦略インターフェース)
trait ExternalMediaStrategy {
def post(message: String)
}
###2. ConcreteStrategy(具体的な戦略役:Twitter)
class TwitterStrategy(
val consumerKey: String,
val consumerSecret: String,
val accessToken: String,
val accessTokenSecret: String,
val debug: Boolean = true
) extends ExternalMediaStrategy {
private lazy val cb = new twitter4j.conf.ConfigurationBuilder()
cb.setDebugEnabled(debug)
.setOAuthConsumerKey(consumerKey)
.setOAuthConsumerSecret(consumerSecret)
.setOAuthAccessToken(accessToken)
.setOAuthAccessTokenSecret(accessTokenSecret)
private lazy val twitter: twitter4j.Twitter = new twitter4j.TwitterFactory(cb.build()).getInstance()
def post(message: String) = {
twitter.updateStatus(message)
}
}
###3. Context(コンテキスト:状況判断)
class ExternalMediaContext {
def contribute()(implicit externalMediaStrategy : ExternalMediaStrategy) = {
val message = "message"
externalMediaStrategy.post(message)
}
}
###4.Client(利用者)
object MyApp extends App{
....
def shareTwitter() = {
implicit val strategy = new TwitterStrategy(
consumerKey,
consumerSecret,
accessToken,
accessTokenSecret,
debug
)
val context = new ExternalMediaContext()
context.contribute()
}
}
ちなみに具体的な戦略役を増やす場合はこんな感じ。
class FacebookStrategy(....) extends ExternalMediaStrategy {
def post(message: String) = {
...
}
}
そんでもってClient(利用者)でこんな感じで呼び出してあげる
object MyApp extends App{
def shareFacebook() = {
implicit val strategy = new FacebookStrategy(....)
val context = new ExternalMediaContext()
context.contribute()
}
}
これなら、Facebook対応する場合もConcreteStrategy(具体的な戦略役)を追加するだけで対応できるでしょう。
今回はTwitterのみ具体的な実装を書きました。
※Twitter4Jを利用してます。
libraryDependencies ++= Seq(
"org.twitter4j" % "twitter4j-core" % "4.0.2"
)