å人ããããããºããã DI ã«ã¤ãã¦æ¸ãã¦ã»ãããã¿ãããªè©±ãã ãã¶åããããã¦ããã ãã©æ¸ãæ°åãã£ã¨ãªãã£ããã§ãä»äºã®æ°å転æã«ã¡ãã£ã¨ãã¤æ¸ãããã¤ãããéã¾ã¨ã¾ã£ãã®ã§å ¬éããã§ãããããããã¨ã¯æ¸ãã¦ãªãã£ã¦ãããç¥ã£ã¦ãã²ã¨ã«ã¯ãããã¾ãã®ãã¨ããæ¸ãã¦ãªãããµã³ãã«ã³ã¼ãã¯ãããã®è¶£å³ã§ Scala ã§æ¸ãã¦ããããJava ãèªããã°ãªãã¨ãªãèªããã¨æãã¾ãã
DI ã£ã¦ãªã«
Dependency Injectionãæ¥æ¬èªã§è¨ãã°ä¾åæ§ã®æ³¨å ¥ã§ããããã¾ãã
ã§è¨äºãçµãã¦ããããã ãã©ãããããä¾åæ§ã¨ã¯ãªããªã®ãããããæ³¨å ¥ããã¨ã¯ã©ããããã¨ãªã®ãããªã DI ãå¿ è¦ã¨ãªãã®ãã¿ãããªè©±ããããããã¾ãã
ããããä¾åæ§ã£ã¦ãªãã«
ä¾ãåºãã¾ããå ¥åãããæååããã¨ã«ãã¿ãããã²ãã¦ããã®çµæã twitter ã«æ稿ããããã°ã©ã ã«ãã¾ãããã
ã¾ãã¯æ®éã«æ¸ãã¦ã¿ã¾ãããã
object Fortune{ def main(args: Array[String]) = { val input = args.head val machine = new FortunePostingMachine() machine.run(input) } }
class FortunePostingMachine { private val fortunes: Seq[String] = IndexedSeq("大å", "ä¸å", "å°å", "å¶", "大å¶") private val twitterClient: TwitterClient = new TwitterClient(/*snip*/) //...(1) def run(input: String): Unit = { val fortune = getFortune(input) twitterClient.updateStatus(fortune) } private def getFortune(input: String): String = { val index = hash(input) % fortunes.length fortunes(index) } private def hash(input: String): Int = { val hashing = scala.util.hashing.Hashing.default hashing.hash(input) } }
class TwitterClient(/*snip*/){ def updateStatus(status: String): Unit = { /* å®éã« Twitter ã«æ稿ããå¦ç */ } }
ãã¦ãããã°ã©ã ã®ã¨ã³ããªãã¤ã³ãã§ãã Fortune
ãªãã¸ã§ã¯ãã®ä»ã«ãFortunePostingMachine
ã¨ããã¯ã©ã¹ã¨ TwitterClient
ã¨ããã¯ã©ã¹ãããã¾ããTwitterClient
ã¯ã©ã¹ã¯ã¡ãã£ã¨å®è£
ãè¤éã«ãªãã®ã§ä¸èº«ã¯æ¸ãã¦ããã¾ããã
ããã§ãFortunePostingMachine
ã«æ³¨ç®ãã¦ã¿ã¾ããããå®éã«ãã¿ãããå¼ãã¦ãtwitter ã«çµæã post ãã¦ãããåã§ããããã®ä¸ã§ãã(1)ã§ç¤ºããé¨åã«æ³¨ç®ãã¦ã¿ã¾ããããFortunePostingMachine
ã®ã³ã³ã¹ãã©ã¯ã¿å
ã§ãTwitterClient
ã¯ã©ã¹ãã¤ã³ã¹ã¿ã³ã¹åãã¦ãã¾ããã¨ãããã¨ã¯ãFortunePostingMachine
ãã³ã³ãã¤ã«ããããã«ã¯ï¼ãããã¯æ£ããåããããã«ã¯ï¼ãTwitterClient
ã¨ããã¯ã©ã¹ãæ£ããåãç¶æ
ã§ãã§ã«å®ç¾©ããã¦ããå¿
è¦ãããã¾ããã
ããããããã¯ã©ã¹Aãã³ã³ãã¤ã«ããããã«ã¯ï¼ãããã¯æ£ããåããããã«ã¯ï¼ãã¯ã©ã¹Bãæ¢ã«åºæ¥ä¸ãã£ã¦ãªãã¨ã ããã¨ããç¶æ ã®ãã¨ãããã¯ã©ã¹Aã¯ã¯ã©ã¹Bã«ä¾åãã¦ãããã¨ãè¨ãã¾ããããããããããã©ã®ã¯ã©ã¹ãã©ã®ã¯ã©ã¹ã«ä¾åãã¦ããã®ãã¨ããæ å ±ãã®ãã¨ãä¾åæ§ã¨å¼ã³ã¾ããä»ã¯ã(1)ã®è¡ã«ä¾åæ§ããã¿æ¸ãããã¦ããç¶æ ã§ããã
ä¾åæ§ããã¿æ¸ãããã¦ããã¨ä½ãã¾ããã®ã
ããããªã±ã¼ã¹ãèãããã¾ããã¾ããåä½ãã¹ãã®ãã«ãããæããããã§ãããããã®FortunePostingMachine
ã«å¯¾ãããã¹ããèµ°ããããã³ã«ãæ¯åå®éã«Twitterã«æ稿ãããã®ã¯ã¡ãã£ã¨ã¾ããã§ãããããªããããããã¾ããã¨ã¢ãã¯ãããã¹ã¿ããããããããªã£ã¦æãã¯ãã§ãã
ãããã¯ãããããããéçºãã¼ã¸ã§ã³ã§ã¯å®éã®Twitterã«æ稿ããããªããã¿ãããªè©±ãããããããã¾ãããããããã¨ãã«ããã¡ãã£ã¨å°ã£ã¡ããã¾ããã
ãã¨ããã®ã¾ã¾ã ã¨ãä»®ã«TwitterClient
ãå£ãã¡ãã£ãã¨ãã«ããã®ã¯ã©ã¹ã®ãã¹ããä¸ç·ã«ããã¡ããã¾ããããã ãè¦ãã¨ããã®ã¯ã©ã¹ãæªãã£ãã®ãããã¨ãTwitterClient
ãæªãã£ãã®ãããããªãã¦å°ã£ã¡ããã¾ããã
ãã®ãããªåé¡ããããä¾åæ§ãã²ã£ãºãããããªããã¨ããçºæ³ãçã¾ããã®ã¯èªç¶ã ã¨è¨ãããã§ãããããããã®ã¾ã¾ã§ã¯FortunePostingMachine
ããTwitterClient
ã¸ã®ä¾åæ§ãã²ã£ãºããã¾ããããªãã§ãããããä¾åæ§ãã¯ã©ã¹ã®ä¸ã«ç´æ¥æ¸ããã¦ãã¾ã£ã¦ããããã§ãããFortunePostingMachine
㯠TwitterClient
ã«ä¾åãã¦ãããã¨ããæ
å ±ããFortunePostingMachine
èªèº«ã®å
é¨ã«æ¸ããã¦ããããã§ããã®ä¾åæ§ãå¤ããã²ã£ãºãããã¨ãã§ããªãã®ã§ãã
ããã§ãããããä¾åæ§ãã¯ã©ã¹ã®å¤ã§å®ç¾©ããã°ããããããªãã®ï¼ãã¨ããçºæ³ãçã¾ãã¦ããããã§ãã大äºãªãã¨ãªã®ã§ããä¸åº¦è¨èãå¤ãã¦è¨ãã¾ãããã¯ã©ã¹Aã«ã¯ã¯ã©ã¹Bãå¿ è¦ã ãã£ã¦ããæ å ±ãã¯ã©ã¹Aèªèº«ã®ä¸ã§å®ç¾©ããã¦ãã¨ãä¾åæ§ãã²ã£ãºãããªãã¦å°ããããããããAãBã«ä¾åãã¦ãããã£ã¦ããæ å ±ããã¯ã©ã¹Aã®å¤ã§å®ç¾©ãã¦å¤ããã¯ã©ã¹Aã®ã¤ã³ã¹ã¿ã³ã¹ã«çªã£è¾¼ãã§ããããããããããªãã®ãã¨ãããã¨ã§ãããã£ã¨ç°¡åã«è¨ãã¨ãä¾åæ§ãå¤ããæ³¨å ¥ãããããã£ã¦ãã¨ã§ããããããã«è¨ã£ã¦ãã¾ãã¨ãDIã£ã¦ã®ã¯ããããçºæ³ã®ãã¨ã§ãã
DI ã®ä¾
ããããå®éã«FortunePostingMachine
ããTwitterClient
ã¸ã®ä¾åæ§ãã²ã£ãºããã¦ã¿ã¾ããããåç´ã«èããã¨ããTwitterClient
ã®ã¤ã³ã¹ã¿ã³ã¹ãFortunePostingMachine
ã®ä¸ã§ã¤ã³ã¹ã¿ã³ã¹åãã¦ãã®ãã¾ãããªããFortunePostingMachine
ã®å¤ã§ã¤ã³ã¹ã¿ã³ã¹åãã¦ãããã渡ãã¦ãããã°ãããï¼ãã¨ããçºæ³ãåºã¦ãã¾ããã³ã¼ãã¯ãããªæãã
object Fortune{ def main(args: Array[String]) = { val input = args.head val twitterClient = new TwitterClient(/*snip*/) //...(1) val machine = new FortunePostingMachine(twitterClient) machine.run(input) } }
class FortunePostingMachine(twitterClient: TwitterClient) { //...(2) private val fortunes: Seq[String] = IndexedSeq("大å", "ä¸å", "å°å", "å¶", "大å¶") def run(input: String): Unit = { val fortune = getFortune(input) twitterClient.updateStatus(fortune) //...(3) } private def getFortune(input: String): String = { val index = hash(input) % fortunes.length fortunes(index) } private def hash(input: String): Int = { val hashing = scala.util.hashing.Hashing.default[String] hashing.hash(input) } }
(2)ã«æ³¨ç®ãã¦ãã ãããFortunePostingMachine
ã¯ã©ã¹ã®ã³ã³ã¹ãã©ã¯ã¿ã§ twitterClient ãåãåãããã«å¤æ´ãããã¨ã§ãå®éã®ã¤ã³ã¹ã¿ã³ã¹åãå¤(1)ã«åºããã¨ãã§ãã¾ããã
ãããããã ãã§ã¯ããºãã§ããã(2)ã§ã¯ã¾ã ãTwitterClient
ãã¨ããåã使ããã¦ã¾ããã(3) ã§ãå®éã« twitterClient ãå©ç¨ãã¦ãã¾ããã¾ã FortunePostingMachine
ã¯ãTwitterClient
ã¯ã©ã¹ããªãã¨ã³ã³ãã¤ã«ã§ããªããæ£ããåããªããã¨ããç¶æ
ã§ããã¤ã¾ããã¾ã TwitterClient
ã¸ã®ä¾åæ§ãæã¡åããã¨ãã§ãã¦ãã¾ããã
ããã§ãä»åº¦ã¯TwitterClient
ã¯ã©ã¹ã®ã»ããã¡ãã£ã¨ãããã¾ãããã
trait TwitterClient{ def updateStatus(input: String): Unit } class TwitterClientImpl(/* snip */) extends TwitterClient { def updateStatus(status: String) = { /*snip*/ } }
TwitterClient
ã¨ããåèªä½ã¯ãclassã§ã¯ãªãã¦traitï¼javaã§è¨ãinterfaceã¿ãããªããï¼ã¨ãã¦ãå®éã®å®è£
㯠TwitterClientImpl
ã®ã»ãã«ç§»ãã¾ãï¼èª¬æã®ããã¨ã¯è¨ãããããã¸ã£ãã¸ã£ãããã³ã¼ãã§ãããªâ¦â¦ï¼ãã¨ãTwitterClient
ã class ã§ã¯ãªããªã£ãã®ã§ãä»ã¾ã§ TwitterClient
ãã¤ã³ã¹ã¿ã³ã¹åãã¦ããé¨åãæ¸ãæããªãã¨ã§ããã
object Fortune{ def main(args: Array[String]) = { val input = args.head val twitterClient: TwitterClient = new TwitterClientImpl(/*snip*/) //...(1) val machine = new FortunePostingMachine(twitterClient) machine.run(input) } }
ãã¦ãããã§ã
FortunePostingMachine
ã®ä¸ã§TwitterClient
åã®ã¯ã©ã¹ã®ã¤ã³ã¹ã¿ã³ã¹ãçæãã¦ããªãFortunePostingMachine
ã¯TwitterClient
åã«ä¾åãã¦ãããã©ãå ·ä½çãªã¯ã©ã¹ã«ã¯ä¾åãã¦ããªã
ã¨ããç¶æ
ãä½ããã¨ãã§ãã¾ãããã¤ã¾ããFortunePostingMachine
ã«ãå¤ããä¾åæ§ã注å
¥ãã¦ããããã¨ãã§ãã¾ããï¼ã
ããã§ãTwitterClientImpl
ãã¾ã ä½ããã¦ãªãã£ãã¨ãã¦ãããã¨ãã°åä½ãã¹ãã®ã¨ãã«ã¯ TwitterClient
ãç¶æ¿ãã MockedTwitterClient
ã¿ãããªãã®ãä½ã£ã¦ããã®ã¤ã³ã¹ã¿ã³ã¹ã FortunePostingMachine
ã«æ¸¡ãããã«ãã¦ãããã°ãã³ã³ãã¤ã«ãã§ãããåä½ãã¹ããã§ãã¾ããããã«ãä»®ã«TwitterClientImpl
ãã¶ã£ãããã¦ããããã«ã¤ããã¦FortunePostingMachine
ã®ãã¹ããè½ã¡ããªãã¦ãã¨ããªããããã§ãã
ãã¦ããããªåç´ãªä¾ã§ããå¤ããä¾åæ§ãæ³¨å ¥ã§ãã¦ãã以ä¸ãç«æ´¾ãª DI ã§ãã
ãã®ä»ã®ææ³
DI ã«ã¯ãããããªæ¹æ³ããã£ã¦ããã£ãã¯ã³ã³ã¹ãã©ã¯ã¿ã§ä¾å対象ã®ãªãã¸ã§ã¯ãã渡ãããã©ãåããããªæãã§ãã¨ãã°ã»ãã¿ã¼ã§ãªãã¸ã§ã¯ãã渡ããã¨ã§ãä¾åæ§ãå¤ããæ³¨å ¥ã§ãã¾ãï¼DIã³ã³ããããã®å½¢å¼ãè¦æ±ããªãéãåãã¹ãã§ã¯ãªãææ³ã ã¨ãããã¯æã£ã¦ãã¾ããï¼ããããã¯ããã Scala ãããæ¸ããªãããããã®ã¯ã©ãã§ããããã
trait FortunePostingMachine { private val fortunes: Seq[String] = IndexedSeq("大å", "ä¸å", "å°å", "å¶", "大å¶") protected val twitterClient: TwitterClient def run(input: String): Unit = { val fortune = getFortune(input) twitterClient.updateStatus(fortune) } private def getFortune(input: String): String = { val index = hash(input) % fortunes.length fortunes(index) } private def hash(input: String): Int = { val hashing = scala.util.hashing.Hashing.default[String] hashing.hash(input) } }
trait TwitterClient{ def updateStatus(input: String): Unit } object TwitterClient { def default(/*snip*/) = new Default(/*snip*/) class Default(/* snip */) extends TwitterClient { def updateStatus(status: String): Unit = { /*snip*/ } } }
object Fortune{ def main(args: Array[String]) = { val input = args.head val machine = new FortunePostingMachine { protected val twitterClient = TwitterClient.default(/*snip*/) } machine.run(input) } }
FortunePostingMachine
ã trait ã«ãã¦ãããã«ã¯ãTwitterClient
åã®ããããã£ãæã£ã¦ãããã¨ããæ
å ±ã ããæ¸ãã¦ããã¾ããnewããã¨ãã«ãã®å ´å®è£
ã§å®éã®twitterClient
ã渡ãã¦ãããã¨ãããã¿ã¼ã³ã§ããããªã«ãã« TwitterClient
ã®ã»ãã Impl ã¨ããããªã㦠TwitterClient
ãªãã¸ã§ã¯ãã®ä¸ã« ãã®ããã©ã«ãå®è£
ã§ãã Default
ã¯ã©ã¹ãå®ç¾©ãã¦ãããã TwitterClient.default
ã§åå¾ã§ããããã«ãã¦ã¿ã¾ãããJava ã ã£ãã TwitterClient ã Abstract Class ã«ãã¦ããã°ä¼¼ããããªãã¨ãå®ç¾ã§ãããã§ããã
ããã§ã DI ãå®ç¾ã§ãã¦ãã¾ãã
ã¾ã¨ã
ä¾åæ§ã£ã¦ãªããªã®
ãã¯ã©ã¹A ãåããããã«ã¯ã¯ã©ã¹Bãå¿ è¦ãã£ã¦ããæ å ±ã®ãã¨
ä¾åæ§ã®æ³¨å ¥ã£ã¦ãªããªã®
ãã¯ã©ã¹A ãåããããã«ã¯ã¯ã©ã¹Bãå¿ è¦ãã£ã¦ããæ å ±ãã¯ã©ã¹Aã®ä¸ã«æ¸ããªãã§å¤ã«æ¸ãã¦å¤ããæ³¨å ¥ã§ããããã«ãããã¨
ä¾åæ§ãæ³¨å ¥ã§ããã¨ãªã«ãããããã®
ã¯ã©ã¹Bããªãã¦ãã¯ã©ã¹Aãåãããããã«ãªããç²çµåã«ãªãããã¹ããããããªããããããã
ãã®ããæ¹
ãããããããè¨èªã®æåã¨ãã«ãã£ã¦å¥½ã¾ããææ³ã¯ç°ãªããä»åã¯ã³ã³ã¹ãã©ã¯ã¿ã§ä¾åæ§ãæ³¨å ¥ãããã¿ã¼ã³ã¨ãæ³¨å ¥å¯¾è±¡ã trait ã«ãã¦ãã㦠new ããã¨ãã«ãã®å ´å®è£ ãããã¨ã§ä¾åæ§ãæ³¨å ¥ãããã¿ã¼ã³ãè¦ã¦ã¿ãã
è¨ãæ®ãããã¨ã¨ã
ãã¦ãããã§ããDI ã£ã¦ãªããªã®ãããªãã§å¿ è¦ãªã®ããã©ãããã®ãã¿ãããªè©±ã«ã¤ãã¦ã¯ä¸éãè¦ããã®ã§ã¯ãªãã§ãããããã§ã話ã¯ããããDIã³ã³ããã£ã¦ãªããªã®ãã¿ãããªã¨ããã«ã¤ãªãã£ã¦è¡ãã®ã§ãããé·ããªã£ãã®ã§ç¶ãã¯ã¾ãä»åº¦ãã£ã¦ãããå¤åæ¸ããªãã¨æããããã¾ã§ããã£ãããDIã³ã³ããã£ã¦ã®ã¯ãä¾åæ§ãæ³¨å ¥ãããå´ã®ã¯ã©ã¹ãè¦ç´éãã«æ¸ãã¦ããã¨ãè¨å®ããã¨ããã« DI ãã¦ãããåã§ããã§éããæ°ãããããæè»ã«æ¸ãã LLç³»è¨èªã¨ã Scala ã¨ããªããããã DI ã³ã³ãããªãã¦å¿ è¦ãªãã¨ãã話ããããã
ãã¨ããªãã§ãããã§ã DI ããã°ããã£ã¦ããã§ããªãã¦ãå¿
è¦ãªã DI ã¯è¨è¨éå°ã¿ãããªæãã§ãããã¯å¥½ã¿ã¾ãããDI ãå¿
è¦ã ãªã¼ã£ã¦æããã¨ãï¼ã¤ã¾ãä¾åæ
å ±ãã¯ã©ã¹å
é¨ããã²ã£ãºãããããªã¼ã£ã¦æã£ãã¨ãï¼ã« DI ããããã«ããã°ããããã§ãã¨ã«ããDIï¼ããªããDIï¼ãã¤ã§ãDIï¼ç²ç®DIï¼ã¿ãããªã®ã¯éãã¨æãï¼å®éä¸è¨ãµã³ãã«ã§ã¯ scala.util.hashing.Hashing.Default
ã¸ã®ä¾åã¯ãã¿æ¸ããã¦ããããªããªããã®ä¾åãã²ã£ãºããå¿
è¦æ§ãæããªãããï¼ã
ãã£ãDependency Injection 㨠Dependency Lookup ã®éãã«ã¤ãã¦ã¯æ¸ãæ°ãããã£ããæ¸ããããããªãã§ãã