ログインしてさらにmixiを楽しもう

コメントを投稿して情報交換!
更新通知を受け取って、最新情報をゲット!

オブジェクト指向研究会!コミュのSingletonとインスタンス変数の併用によるメリット

  • mixiチェック
  • このエントリーをはてなブックマークに追加
現状の設計では、Propertiesファイルを読み込みインスタンスをフィールドに保持しpublicなgetメソッドが呼ばれたときにkeyを使って必要な値を戻す「PropUtils」なるクラスが存在する。
これは1つのアプリケーションのプロパティ(設定値)を外部ファイル1つにまとめることで変更時の柔軟性をあげるための手段として取り入れたわけだけど、ぶっちゃけ今回の掲示板だと記述しているのはSQL文とDB関連情報くらいなので変更する可能性はほとんどない。
そもそもアジャイル開発手法とか言いつつ、変更を事前に予測したクラス設計をするのもどうかとおもうわけだけど、研究会による研究と検証ってことでその辺はご勘弁w


で。
メンバーであるD君に、この「PropUtils」をコーディングしてもらった結果シングルトンパターンとインスタンス変数でPropertiesのインスタンスをフィールドに持たせる形での実現がされました。

ここで、ある疑問を顧問の先生から投げかけられる。


「シングルトンクラスは1つのインスタンスしか持たないわけだけど、だったらフィールドのインスタンス変数をstaticにしても同じだよね。どっちがいいんだろね」
と。

そこで、マーチンファウラー著の「エンタープライズアプリケーションアーキテクチャ」の第18章ベースパターン項目のスレッドセーフレジストリの部分を参考に昨夜その場にいたメンバーで議論した結果まがりなりにも「仮答え」的なものがでたのでここで報告を。



・シングルトンとインスタンス変数を合わせることで得られるメリットとは

そもそも、ファイラーのいうレジストリがどんなものを指しているのかこの部分だけだと僕的に出た答えは

P.506下部にある「メソッドをレジストリに配置してレジストリをスタブモードで初期化し、スタブの振る舞いをサブクラスに保持することによって、テストに必要なコードを分離することができる」

これがそのまんま、そうなのかなと。

ソースコードを実際に書いて説明しますと・・・



class Registry{
protected PersonFinder personFinder = new PersonFinder();
private static Registry soleInstance = new Registry();

private static Registry getInstance(){
//静的な自身のインスタンスを返す
return soleInstance;
}

public static void initialize(){
//レジストリの再初期化
soleInstance = new Registry();
}

public static void initializeStub(){
//サブクラスの代入
soleInstance = new RegistryStub();
}

public static PersonFinder personFinder(){
//自身のインスタンスのインスタンス変数を参照
return getInstance().personFinder;
}
}
class RegistryStub extends Registry{
public RegistryStub(){
Soleinstance = new Sub();
}
}
class Sup{
//コードA
}

class Sub extends Sup{
//コードB
}


コードBをテストコードとして利用するもよし、Registryクラスのサブクラスを複数作って用途ごとに分けてManegerで管理するもよし。みたいな。

インスタンス変数の中身が違うRegistryクラスは常に1つで用途ごとにインスタンス変数の中身を変更していくわけだけど、同じ静的な値を使えると。

ファウラーのいう「置換」ってこういうことなんじゃないですかねぇ?

コメント(6)

このソースはコンパイルエラーになるべつ。
class Client {
    public static void main(String[] args) {
        Registry.initialize();
        PersonFinder finder=Registry.personFinder();
        finder.someOperation();
        
        Registry.initializeStub();
        finder=Registry.personFinder();
        finder.someOperation();
    }

}
class Registry {
    protected PersonFinder personFinder = new PersonFinder();
    private static Registry soleInstance = new Registry();

    private static Registry getInstance() {
        // 静的な自身のインスタンスを返す
        return soleInstance;
    }
    public static void initialize() {
        // レジストリの再初期化
        soleInstance = new Registry();
    }
    public static void initializeStub() {
        // サブクラスの代入
        soleInstance = new RegistryStub();
    }
    public static PersonFinder personFinder() {
        // 自身のインスタンスのインスタンス変数を参照
        return getInstance().personFinder;
    }
}

class RegistryStub extends Registry {
    public RegistryStub() {
        this.personFinder=new PersonFinderStub();
    }
}
//レイヤースーパークラス
abstract class DomainFinder{}
class PersonFinder extends DomainFinder{
    public void someOperation(){}
}
class PersonFinderStub extends PersonFinder{
    public void someOperation(){}
}

正しくは、上のような感じだべつ。それと、ちゃんとソースのインデントを入れておかないと見にくいべつ。タブやスペースを入れて投稿しても、mixiのシステムは、実体参照( など)に置き換えてくれないようなので、ソースをアップするときに、インデント部分を自分で実体参照に置き換えて投稿する必要があるべつ。そうすると、上のサンプルのようにちゃんとインデントが保持できるべつ。mixiのシステムは、タブやスペースが入力されても自動的に実体参照には置き換えてくれないけど、逆に実体参照を入力して投稿してもエスケープされないようになっているべつ。これは、mixiのシステムの仕様べつ。勉強になるべつ。
で、本当の問題は、上のソースを次のように変更してもいいのではないか、という点だべつ。
つまり、

class Client {
    public static void main(String[] args) {
        Registry.initialize();
        PersonFinder finder=Registry.personFinder();
        finder.someOperation();
        
        Registry.initializeStub();
        finder=Registry.personFinder();
        finder.someOperation();
    }

}
class Registry {
    //クラス変数にしてもいいのでは?
    //これが、問題になっていたのでは?
    protected static PersonFinder personFinder = new PersonFinder();
    private static Registry soleInstance = new Registry();

    private static Registry getInstance() {
        // 静的な自身のインスタンスを返す
        return soleInstance;
    }
    public static void initialize() {
        // レジストリの再初期化
        soleInstance = new Registry();
    }
    public static void initializeStub() {
        // サブクラスの代入
        soleInstance = new RegistryStub();
    }
    public static PersonFinder personFinder() {
        // 自身のインスタンスのインスタンス変数を参照
        return getInstance().personFinder;
    }
}

class RegistryStub extends Registry {
    public RegistryStub() {
        this.personFinder=new PersonFinderStub();
    }
}
abstract class DomainFinder{
}
class PersonFinder extends DomainFinder{
    public void someOperation(){}
}
class PersonFinderStub extends PersonFinder{
    public void someOperation(){}
}

Registryクラス内のインスタンス変数をクラス変数にしても全く問題なく、同じ機能を提供できる。これは、どちらが良いのか、というのが問題だったのでは?

protected PersonFinder personFinder = new PersonFinder();
    ↓
protected static PersonFinder personFinder = new PersonFinder();

もし、このことが問題だったのだとしたら、ニラの答えでは解答になっていないべつ。

もし、とんじろうの勘違いで、問題の意味が他のことならば、また、話は別だべつ。
この問題について誰も書き込まないべつ?
ええと、少し時間ができたのでちょっとだけ・・。
やっぱり、PersonFinderがインスタンス変数だからこそ得ることができるメリットっていうのは

「テストコードが書かれたPersonFinderStub(PersonFinderのサブクラス)をRegistryStub(Registryのサブクラス)のpersonFinder変数に代入することでテストコードを利用しつつ、共通のstaticな変数を扱えるテストクラスとして機能する」

のかなと思うんですよ。
もちろん、その場合でも元のRegistryクラスは通常通り機能するわけだし。

うーん、どうっすかねぇ?
すまんべつ。以下の部分をサンプルをつけて詳しく説明して欲しいべつ。

「テストコードが書かれたPersonFinderStub(PersonFinderのサブクラス)をRegistryStub(Registryのサブクラス)のpersonFinder変数に代入することでテストコードを利用しつつ、共通のstaticな変数を扱えるテストクラスとして機能する」

ログインすると、みんなのコメントがもっと見れるよ

mixiユーザー
ログインしてコメントしよう!

オブジェクト指向研究会! 更新情報

オブジェクト指向研究会!のメンバーはこんなコミュニティにも参加しています

星印の数は、共通して参加しているメンバーが多いほど増えます。

人気コミュニティランキング