Index: [Article Count Order] [Thread]

Date:  Sat, 10 Jun 2000 22:50:14 +0900
From:  "Ken N." <kenn@....nu>
Subject:  [XP-jp:00520] Re: XP Installed26 Part1 Test-first, by Intetion
To:  extremeprogramming-jp@....jp (extremeprogramming-jp ML)
Message-Id:  <200006101349.WAA31357@....nu>
In-Reply-To:  Your message of "Mon, 5 Jun 2000 00:21:16 +0900".    <393A7391300.1D1EY-KAMITE@....jp>
Posted:  Sat, 10 Jun 2000 22:49:59 +0900
X-Mail-Count: 00520

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