からくりがてんこ

IT関連情報、プログラミングに関する作業ログや備忘録を記載していきます。

C言語からの本当のJava言語へ (Singleton)

次に紹介するのはシングルトンパターンです。
何となく聞いたことはあるけどよく知らないなぁって方もいるかも知れません。

ザックリ言うとシステム上オブジェクトが1つだけパターン。そんな感じです。
はぁ。。。それは結局何がよくて、どう使えばいいの?
それについて例を交えながら紹介していきます。

Singleton

これはよくシステム上一つだけしか存在しないオブジェクトの設計に使われますが、どんな時に使えばいいか分からない。。

そんな時は、1つ「だけ」でなく1つで「よい」と考えてみるのも一つの手です。

プロパティファイルなんてどうですか?
システム上1つでよくないですか?

プロパティファイルを保持するクラスがある場合、同じプロパティの値を持ったオブジェクトを複数個生成する必要はないでしょう。
プロパティファイルの変更を動的に対応する仕様なら別ですが、大体のシステムは、プロパティファイル変更時は再起動しますよね。

なので、プロパティファイルオブジェクトはシステム上1つオブジェクトがあれば事足ります。
プロパティファイル管理クラスをSingletonパターンで実装してみましょう。

複数個生成しないということはオブジェクトの生成するコストが下がります。

まぁ四の五の言わず、サンプルを見てみましょう。

public class PropertyClass {
    // 自身のプロパティを保持する領域をスタティックで
    private static PropertyClass instance = new PropertyClass();
    
    private String name;
    private String age;
    
    private PropertyClass() {
        // インスタンス生成時のみ初期化
        this.init();
    }
    
    public static PropertyClass getInstance() {
        return instance;
    }
    
    private void init() {
        // 初期化処理をしましょう
        // プロパティファイルを読込んでメンバ変数に格納する…
    }

    /** getter(メンバ変数の取得メソッド) **/
    public String getName() {
        return name;
    }
    public String getAge() {
        return age;
    }
}

Singletonでのポイントは

コンストラクタがprivateなので、他のクラスから"new"できません。
getInstanceメソッドでオブジェクトを取得することができるのですが、クラスロード時に"new"された、staticで保持しているオブジェクトが返る事になります。
このような仕組みでシステム上で1つしかオブジェクトが存在しないことが保証されているのです。

当然、実装によっては2つしか存在しないというような設計にできるでしょう。
オブジェクトの数を制限できることが、Singletonパターンのよい所というのが私の持論です(Singletonパターンという名前からはちょっとずれちゃいますが…)

では、検証がてらプロパティクラスを使用しているメインクラスも見てみましょう。

public class TestMain {

    public static void main(String[] args) {
        PropertyClass property1 = PropertyClass.getInstance();
        PropertyClass property2 = PropertyClass.getInstance();

        System.out.println("出力結果 : " + property1);
        System.out.println("出力結果 : " + property2);
    }
}

それを実行した結果はこうなります。

出力結果 : PropertyClass@56e5b723
出力結果 : PropertyClass@56e5b723

変な文字列がならんでいますが、これはオブジェクトのアドレスだと思って大丈夫です。
property1もproperty2も同じアドレスを参照していますね。
プロパティクラスのオブジェクトは1つしか生成されていないということです。

もう一つ、Singletonパターンを使用することで良い点は、シングルトンクラスを利用する側での誤りを減らす事ができるということです。
大人数でプログラムを作成する場合、他人の作成したクラスを使用することも多いと思います。
それがもし、複数オブジェクトを作成してはいけませんよという注意があったとしても、誤って生成してしまうこともあるでしょう。
また、システム上1つであるということを利用する側が意識した実装をしなければいけません。

そういった場合、Singletonクラス側で生成方法を制御し、オブジェクト数を保証しておけば開発者の負担も軽減されます。

どうでしょう、理解の手助けになったでしょうか。
あなたの設計にも、Singletonパターンをお一ついかがでしょう。

<<コラム:staticって>>
「staticってよく分かんないや〜」って方へのザックリ解説

javaのメモリ領域には大きく3つ広場があります。

クラス領域

java起動後プログラムが終了するまで消えない領域です。
クラス情報staticで宣言された情報が置かれます。

ヒープ領域

newされたオブジェクトが置かれる領域です。オブジェクトが参照されなくなると消されます。参照されないというのはnull代入が該当します。(即時消される訳ではありません。掃除屋が定期的に消しに来ます。ガベージコレクション)

スタック領域

主にメソッドの引数が格納される領域で、メソッドが終了すると消されます。





クラス領域とヒープ領域のイメージを見てみましょう。(スタック領域は置いといて…)
f:id:ayumu-homes:20140121113133p:plain

クラス領域はjava起動時にクラスローダーからクラス情報やstatic情報がロードされます。
オブジェクトを生成した時、俗に言う"new"された時、その情報を元にヒープ領域にオブジェクトが生成されます。
赤い部分がstatic宣言された変数で黒い部分がstatic宣言されていない(まぁ普通の宣言)を表しています。見てみると各オブジェクトには赤い領域は入ってませんね。

ClassA.type

と書けて

ClassA.name

と書けないと言われていますが、static変数やstaticメソッドがオブジェクトを生成しなくても使える理由がなんとなく分かりませんか?「ClassAのnameってどれだよ!」ってなっちゃいますよね。"object1.name"なら分かりますね。

staticの情報というのは生成されたオブジェクトでなくクラス情報に紐づいた情報なのです。

static {
    type = "human";
}

ちなみに、プログラム中でこのような書き方で、クラスロード時にstatic変数の初期化なんかもできるのですが、このブロックの名前を「スタティックイニシャライザー」と言います。なんか必殺技っぽくてカッコ良くないですか…?