Java小ネタ

最近技術系のネタを書いてないなぁと思ったので。

Javaで、複数のプロパティをアクセサメソッドでセットして使うというケースはよくあるかと思われるのですが、

class SomeData {
    private int _foo;
    private double _bar;
    private String _baz;

    void setBar( double bar ) {
        _bar = bar;
    }

    void setBaz( String baz ) {
        _baz = baz;
    }

    void setFoo( int foo ) {
        _foo = foo;
    }
}

を、

SomeData data = new SomeData();
data.setFoo( 12 );
data.setBar( 34.0 );
data.setBaz( "56" );

someMethod( data );

みたいな感じで。

これだとなんか微妙だな、と思うわけですよね。引数を指定するだけのインスタンスがそのスコープが終わるまでHeapに残るのが気に入らないとか。


一番Javaっぽく対応するとしたら、コンストラクタで引数を取る方法が、

class SomeData2 {
    private int _foo;
    private double _bar;
    private String _baz;

    public SomeData2( int foo , double bar , String baz ) {
        _foo = foo;
        _bar = bar;
        _baz = baz;
    }
}

で、

someMethod( new SomeData2( 12 , 34.0 , "56" );

となるのですが、コンストラクタを使うと、引数が多くなった場合に分かりづらいとか(あまりプロパティを多くするなよという設計もあるかとは思いますが)、同じ型のプロパティをそれぞれどちらかを指定するコンストラクタを作りたいケース(以下参照)とかで困ってしまうこともあったりなかったりしたりして。

class SomeData3 {
    private int _foo;
    private String _bar;
    private String _baz;

    public SomeData3( int foo , String bar ) {
        _foo = foo;
        _bar = bar;
    }

    public SomeData3( int foo , String baz ) {
        _foo = foo;
        _baz = baz;
    }
}

(こういうケース)


で、この問題に対応した方法として、メソッドチェーン(これしきで流れるようなインターフェイスとか名乗れないのですよ)があって、

class SomeData4 {
    private int _foo;
    private double _bar;
    private String _baz;

    SomeData4 setBar( double bar ) {
        _bar = bar;
        return this;
    }

    SomeData4 setBaz( String baz ) {
        _baz = baz;
        return this;
    }

    SomeData4 setFoo( int foo ) {
        _foo = foo;
        return this;
    }
}

で、

someMethod( new SomeData4().setFoo( 12 )
                           .setBar( 34.0 )
                           .setBaz( "56" ) );

みたいな感じ。


これはなかなか良い手法だと思ってるのですが、当然対応しているクラスじゃないと使えないわけです。
んで、

を見てたら、Instance initializerを使うといいのでは、と思いました。

someMethod( new SomeData() { {
    setFoo( 12 );
    setBar( 34.0 );
    setBaz( "56" );
} } );

いかがでしょうか?