2005-06-02(Thu) [長年日記]
■1 車輪の再実装: 簡易DIコンテナ on Groovy
Groovyで、クラスの数が10〜15程度の規模で書かれたコードをDRY原則に従ってリファクタしていると、EoT(Ease of Testing:テスト容易性)の観点からDIコンテナが欲しくなってきた。
しかし、この規模のコードではSeasar2はおろか、PicoContainerですらヘビーウェイト。なので、id:t-wadaさんとTDD && ペアプロで作成してみた。
機能としてはAOPもXMLによる設定も無く、オブジェクトのwiringだけだが、我われの現在の用途には必要十分。インジェクション方法は、ブロック・インジェクション——Groovyだからクロージャ・インジェクションと呼ぶべきか——のみをサポート。車輪の再実装は善。って、『Linux mgazine』(2005.02)のMatzダイコンを丸パクリなので、再実装ですらないか。
利用イメージ
こんな感じ:
class Blog {
input
display
...
}
class Input {...}
...
dicon = new DICon()
dicon.regist("blog") {|c| new Blog(input:c.input(), display:c.display)}
dicon.regist("input") {|c| new Input()}
dicon.regist("display") {|c| new Display()}
blog = dicon.blog # dicon.blog() でも良い
blog.display...
テストコード
ガリガリ書き流したので安直だったりコピペだったりで手抜き。「Code as Documentation」になってない。
1 package com.kakutani.groovy.di
2
3 class DIConTest extends GroovyTestCase {
4 dicon
5
6 void setUp() {
7 dicon = new DICon()
8 }
9
10 void testOneCompoent() {
11 dicon.regist("myString") { "Hello World" }
12 assertEquals("Hello World", dicon.myString)
13 }
14
15 void testTwoCompoent() {
16 dicon.regist("myString") { "Hello World" }
17 dicon.regist("foo") { "Hello Foo" }
18 assertEquals("Hello Foo", dicon.foo)
19 }
20
21 void testDependency() {
22 dicon.regist("lineItem") { "ThinkPad"}
23 dicon.regist("order") {|c|
24 order = []
25 order[0] = c.instance("lineItem")
26 order
27 }
28
29 assertEquals("ThinkPad", dicon.instance("order")[0])
30 }
31
32 void testPropertyMissing() {
33 dicon.regist("lineItem") { "ThinkPad" }
34 dicon.regist("order") {|c|
35 order = []
36 order[0] = c.lineItem
37 order
38 }
39
40 assertEquals("ThinkPad", dicon.order[0])
41 }
42
43 void testMethodMissing() {
44 dicon.regist("lineItem") { "ThinkPad" }
45 dicon.regist("order") {|c|
46 order = []
47 order[0] = c.lineItem()
48 order
49 }
50
51 assertEquals("ThinkPad", dicon.order()[0])
52 }
53 }
プロダクトコード
Classic Syntax。JSR Syntaxは気にくわない、というのもあるけれど、MarkupとBuilderが使えないと困るので、beta10を採用。
行数は39行。所要時間は、mixiの日記のタイムスタンプから算出すると29分。getPropertyとinvokeMethodのオーバーライドでハマった(自分で翻訳していたというのに)。メソッドの仮引数の型を明示しないとオーバーライドできないのね……。
ちなみに、ブロック・インジェクションなMatzダイコンはRubyで20行。
1 package com.kakutani.groovy.di
2
3 class DICon {
4 instances
5 services
6
7 DICon() {
8 instances = [:]
9 services = [:]
10 }
11
12 DICon regist(name, closure) {
13 services[name] = closure
14 this
15 }
16
17 Object instance(name) {
18 if (instances[name] != null) return instances[name]
19 closure = services[name]
20 component = closure.call(this)
21 instances[name] = component
22 }
23
24 getProperty(String name) {
25 try {
26 return metaClass.getProperty(this, name)
27 } catch(MissingPropertyException e) {
28 return instance(name)
29 }
30 }
31
32 invokeMethod(String name, Object args) {
33 try {
34 return metaClass.invokeMethod(this, name, args)
35 } catch(MissingMethodException e) {
36 return instance(name)
37 }
38 }
39 }
さらに先に進むために
GroovyでAOPというかインターセプターというか、そーゆうのを仕込もうと思ったらどういうやり方があるのかなあ……。AspectGとか無いのかな。
■2 TodoListTutorial with Rails
id:babieさんによる翻訳。お疲れさまでしたッ!
リーン開発の現場 カンバンによる大規模プロジェクトの運営(Henrik Kniberg/角谷 信太郎/市谷 聡啓/藤原 大)
『なるほどUnixプロセス ― Rubyで学ぶUnixの基礎』
SCRUM BOOT CAMP THE BOOK(西村 直人/永瀬 美穂/吉羽 龍太郎)
実践テスト駆動開発 テストに導かれてオブジェクト指向ソフトウェアを育てる(Steve Freeman/Nat Pryce/和智 右桂/高木 正弘)
The RSpec Book (Professional Ruby Series)(David Chelimsky/Dave Astels/Zach Dennis/角谷 信太郎/豊田 祐司/株式会社クイープ)
アジャイルサムライ−達人開発者への道−(Jonathan Rasmusson/西村 直人/角谷 信太郎/近藤 修平/角掛 拓未)
アジャイルな見積りと計画づくり ~価値あるソフトウェアを育てる概念と技法~(Mike Cohn/マイク コーン/安井 力/角谷 信太郎)
インターフェイス指向設計 ―アジャイル手法によるオブジェクト指向設計の実践(Ken Pugh/角谷 信太郎(監訳)/児島 修)
アジャイルプラクティス 達人プログラマに学ぶ現場開発者の習慣(Venkat Subramaniam/Andy Hunt/木下 史彦/角谷 信太郎)
JavaからRubyへ ―マネージャのための実践移行ガイド(Bruce A. Tate/角谷 信太郎)










ども。実は、このチュートリアル、原文のコード見るだけでも、十分わかりやすいんですけどねw。
http://d.hatena.ne.jp/Kazzz/20050607/p1<br>Kazzの「JとNの狭間で」<br>[Java]LightWeight DIContainer on Groovy<br> [http://www.kakutani.com/20050602.html#p01:title] Javaではなく正確にはGroovyなのだけれどDIコンテナを実装してみました、というお話し。 私が知っている中では最軽量のDIコンテナと思います。 AOPもXMLによる設定も無く、オブジェクトのwiringだけなのだそうだけど..
http://kakutani.com/20050621.html#p02<br>角谷HTML化計画<br>車輪の再実装: 簡易DIコンテナ on Groovy with AOP<br>今度はGroovyダイコンに簡易AOP機能を実装してみた。コンテナ部分のコードは45行増えて84行に。