Part1と2についてコードをJavaにしてみました。
どの程度妥当な訳になっているかあまり自信はありませんが、参考になれば。
まずはPart1のほうです。
<Smalltalk>
=== Page 190 Code 1
Object subclass:#Sum
instance variables:'name amount'
</Smalltalk>
<Java>
=== Page 190 Code 1
/*
Smalltalkではクラスにメッセージを送ることによってサブクラ
スを導出します。適当な基底クラスが見付からなければ
``Object'' にメッセージを送ることになります。意味としては
新規クラスの定義ですので、Javaならば以下のように書けば十分
でしょう。
*/
class Sum {
private String name;
// 後になって登場するコードを見る限りでは、nameはString
// で良いと思われます。
private int amount;
// amountについては、とりあえずintにしておきました。
// メソッドの定義は後で出て来ます。ここではブランクにして
// おきます。
}
</Java>
<Smalltalk>
=== Page 191 Code 1
^self new
setName:aString
amount:aNumber
</Smalltalk>
<Java>
=== Page 191 Code 1
/*
本文の記述をみればわかる通り、上記のSmalltalkコードは、メソッ
ドの本体部分だけです。しかし、「コンストラクタ」と明記され
ていますので、以下のように書けます。
*/
public Sum(String aString, int aNumber){
setNameAndAmount(aString, aNumber);
}
</Java>
<Smalltalk>
=== Page 191 Code 2
name:aString amount:aNumber
^self new
setName:aString
amount:aNumber
</Smalltalk>
<Java>
=== Page 191 Code 2
/*
すでに上述のとおりですが、ファクトリメソッドのほうが意味的
に近いかもしれません。こんなふうに書けると思います。(でも、
いかにも「直訳」という感じですね)
*/
private Sum(){}
public static Sum createWithNameAndAmount(String aString, int aNumber){
Sum aNewSum = new Sum();
aNewSum.setNameAndAmount(aString, aNumber);
return aNewSum;
}
</Java>
<Smalltalk>
=== Page 191 Code 3
setName:aString amount:aNumber
name:=aString
amount:=aNumber
</Smalltalk>
<Java>
=== Page 191 Code 3
/*
「新しいインスタンスを作って初期化する」という処理から「イ
ンスタンスを初期化する」という処理を分離するのが彼らの流儀
のようです。
直訳すると以下のようになるでしょう。
*/
public Sum setNameAndAmount(String aString, int aNumber){
name = aString;
amount = aNumber;
return this;
}
/*
しかし、実際にはつぎのようなものでも十分かもしれません。
*/
private /* or protected */ void setNameAndAmount(String aString, int aNumber){
name = aString;
amount = aNumber;
}
</Java>
<Smalltalk>
=== Page 192 Code 1
name
^name
</Smalltalk>
<Java>
=== Page 192 Code 1
// 特に説明は不要だと思います。
public String getName(){ return name; }
</Java>
<Smalltalk>
=== Page 192 Code 2
amount
^amount
</Smalltalk>
<Java>
=== Page 192 Code 2
public int getAmount(){ return amount; }
</Java>
<Java>
/*
彼らは、ここまでで一旦``Sum''の実装に一区切りつけています
から、一応まとめておきます。
*/
class Sum {
private String name;
private int amount;
public Sum(String aString, int aNumber){ setNameAndAmount(aString, aNumber); }
public Sum setNameAndAmount(String aString, int aNumber){
name = aString;
amount = aNumber;
return this;
}
public String getName(){ return name; }
public int getAmount(){ return amount; }
}
</Java>
つづいてPart2のほうです。
<Smalltalk>
=== Page 193 Code 1
testEmpty
|summarizer|
summarizer:=self emptySummarizer.
</Smalltalk>
<Java>
=== Page 193 Code 1
/*
Summarizerクラスの実装に入る前に、そのクラスのテストを先に
書くことから始めているわけですね。本章の主題でもあります。
さてと... JUnitを使うことにしましょうか。
class SummarizerTest extends TestCase {
...
}
などとしてあるものとします。
*/
public SummarizerTest testEmpty(){
Summarizer summarizer = emptySummarizer();
// 未完です
return this; // voidでもいいと思います。
}
</Java>
<Smalltalk>
=== Page 193 Code 2
testEmpty
|summarizer|
summarizer:=self emptySummarizer.
self should:[summarizer summary isEmpty]
</Smalltalk>
<Java>
=== Page 193 Code 1
/*
``should:''キーワードメソッドは、受け取ったブロッククロー
ジャにvalueメッセージを送り、Trueのインスタンスが返ってこ
なければエラーとするものだと推測できます。以下のように書け
ると思います。
*/
public SummarizerTest testEmpty(){
Summarizer summarizer = emptySummarizer();
assert(summarizer.summary().isEmpty());
return this; // voidでもいいと思います。
}
/*
しかし、両者の違いについては知っておいたほうがいいでしょう。
上記Javaコードではassertには評価された後の値、つまり、真ま
たは偽が渡りますが、前出のSmalltalkコードでは、真偽の獲得は
should:キーワードメソッドの中で行なわれることになります。
*/
</Java>
<Smalltalk>
=== Page 194 Code 1
Object subclass:#Summarizer
instance variables:'first second'
</Smalltalk>
<Java>
=== Page 194 Code 1
/*
ここで彼らは一旦Summarizerクラスに注意を向けています。とい
っても、クラスの属性を定義しただけで、すぐにテストの続きに
戻っています。
属性の型をどうするかというのが問題です。後で出てくる
OrderedCollection と同じにしておくのが無難そうですが、Java
で何を使うのが適当かよくわからないので、仮に FooCollection
とでもしておきます。
*/
class Summarizer {
private FooCollection first;
private FooCollection second;
}
</Java>
<Smalltalk>
=== Page 194 Code 2
emptySummarizer
^Summarizer
with:#()
with:#()
</Smalltalk>
<Java>
=== Page 194 Code 2
/*
SummarizerTestのなかにemptySummarizer()を定義します。
privateでいいでしょう。
仮に設定したFooCollectionを引数無しのコンストラクタで構築
すると、空のコレクションができるものと仮定して、次のように
書けます。
*/
private Summarizer emptySummarizer(){
return new Summarizer(new FooCollection(), new FooCollection());
}
</Java>
<Smalltalk>
=== Page 195 Code 1
with:firstCollection with:secondCollection
^self new
setFirstCollection:firstCollection
secondCollection:secondCollection
</Smalltalk>
<Smalltalk>
=== Page 195 Code 2
setFirstCollection:firstCollection secondCollection:secondCollection
first:=firstCollection
second:=secondCollection
</Smalltalk>
<Java>
=== Page 195 Code 1
=== Page 195 Code 2
/*
前出のSumの場合と同様です。ここまでのSummarizerをまとめて
みます。
*/
class Summarizer {
private FooCollection first;
private FooCollection second;
public Summarizer(FooCollection firstCollection, FooCollection secondCollection){
setFirstAndSecondCollection(firstCollection, secondCollection);
}
public Summarizer setFirstAndSecondCollection(FooCollection firstCollection, FooCollection secondCollection){
first = firstCollection;
second = secondCollection;
return this; // void でもいいでしょう。
}
}
</Java>
<Smalltalk>
=== Page 195 Code 3
summary
self halt
</Smalltalk>
<Java>
=== Page 195 Code 3
/*
Javaではどうするのがいいのかよくわかりません。デバッガを使
うために実行の停止をさせたいということですから、最初からデ
バッガの中で動かすことにして、このメソッドにブレークポイン
トを設定しておけばいいと思います。
*/
public void summary(){}
</Java>
<Smalltalk>
=== Page 195 Code 4
summary
^first,second
</Smalltalk>
<Java>
=== Page 195 Code 4
/*
仮の実装として、ふたつのCollectionを連結して返すと言う処理
を記述しています。
うーん、くるしまぎれですが、FooCollectionではconcat()メソッ
ドで別のインスタンスを連結できるということにしておきます。
また、concat()はレシーバ自身を返すものとします。
*/
public FooCollection summary(){ return first.concat(second); }
/*
また、
= 空の collection を書いてそれを返す方がより単
= 純だが、
ということでやってみると、以下の通りです。
*/
public FooCollection summary(){ return new FooCollection(); }
</Java>
<Smalltalk>
=== Page 196 Code 1
testABC
"self unsafeRun:#testABC"
|summarizer|
summarizer:=self abcSummarizer.
self should:[summarize summary size=3]
</Smalltalk>
<Java>
=== Page 196 Code 1
/*
ここで新たなテストを追加しています。
単項メッセージの優先順位が最高ですので、次のように書けます。
*/
public SummarizerTest testABC(){
Summarizer summarizer = abcSummarizer();
assert(summarize.summary().size() == 3);
return this;
}
/*
FooCollectionのsize()メソッドは、コレクションの要素数を返すも
のであると仮定しています。
*/
</Java>
<Java>
/*
ここまでで、各クラスがどうなったかをまとめておきます。
勝手に想定したFooCollectionクラスのせいで、わかりにくくなっ
ている部分がありますね... Javaでの適切なコレクションクラス
をご存知のかたは、どんどん書き換えてください。
*/
class Sum {
private String name;
private int amount;
public Sum(String aString, int aNumber){ setNameAndAmount(aString, aNumber); }
public Sum setNameAndAmount(String aString, int aNumber){
name = aString;
amount = aNumber;
return this;
}
public String getName(){ return name; }
public int getAmount(){ return amount; }
}
class SummarizerTest extends TestCase { // JUnitの使用を想定している。
public SummarizerTest(String name){ super(name); }
// setUp()とtearDown()は、このケースでは省略できると思います。
public SummarizerTest testEmpty(){
Summarizer summarizer = emptySummarizer();
assert(summarizer.summary().isEmpty());
return this; // voidでもいいと思います。
}
private Summarizer emptySummarizer(){
return new Summarizer(new FooCollection(), new FooCollection());
}
public SummarizerTest testABC(){
Summarizer summarizer = abcSummarizer();
assert(summarize.summary().size() == 3);
return this; // voidでもいいと思います。
}
}
class Summarizer {
private FooCollection first;
private FooCollection second;
public Summarizer(FooCollection firstCollection, FooCollection secondCollection){
setFirstAndSecondCollection(firstCollection, secondCollection);
}
public Summarizer setFirstAndSecondCollection(FooCollection firstCollection, FooCollection secondCollection){
first = firstCollection;
second = secondCollection;
return this;
}
public FooCollection summary(){ return first.concat(second); }
}
</Java>
Part3/4で出てくる``do:[...]''や``detect:[...] ifNone:[...]''を
どう訳すのが適切か、ちょっと考えているところです。
-.- . -. -.
Ken Nakagaki (kenn@....nu is NOT for private E-Mail)
「人は船ではない。人は会社ではない」-- Gerry Spence