0
1

More than 3 years have passed since last update.

【Effective Javaを読む】 第2章 項目3 『privateのコンストラクタかenum型でシングルトン特性を強制する』

Last updated at Posted at 2020-07-26

privateのコンストラクタかenum型でシングルトン特性を強制する

Java1.5より前ではシングルトンを実装する方法が2つあった(例1、例2)けど、1.5でできるようになった3つ目の方法(例4)が一番良いねってお話。

用語集

シングルトン

デザインパターンの一種。
「Singleton(シングルトン)パターン」と呼ばれることもある。
手短に言えば厳密に一度しかインスタンスが作成されないクラス。
「あるクラスのインスタンスが常にたった1つしか存在していない」という状態を実現したいときに利用される。

シングルトンの作り方
・コンストラクタをprivateで宣言する。
 (このクラスを利用する側からコンストラクタを呼び出せないようにするため)

・インスタンスを取得するメソッドgetInstance( )をstaticで宣言する。
 これにより、利用側はSingleton#getInstance( )という呼び出しでインスタンスを取得することができる。

シングルトンサンプル
/**
 * アプリケーション全体の設定情報
 */
public class Config {
    /**
     * 外部からインスタンス化できないよう、コンストラクタをprivateで宣言する
     */
    private Config() {
        // 実際はファイル・データベースなどから設定情報を
        // 読み込む処理をここに書く
    }

    /**
     * 唯一のインスタンスを返す
     * @return このクラスの唯一のインスタンス
     */
    public static Config getInstance() {
        return ConfigInstanceHolder.INSTANCE;
    }

    /**
     * 指定されたキーに対応する設定値を返す
     * @param key 設定キー
     * @return 設定値
     */
    public String getValue(String key) {
        // 実際はコンストラクタで読み込んだ設定情報を
        // 返す処理をここに書く
        return ....;
    }

    /**
     * Configクラスの唯一のインスタンスを保持する内部クラス
     */
    public static class ConfigInstanceHolder {
        /** 唯一のインスタンス */
        private static final Config INSTANCE = new Config();
    }
}

enum型

Enum(列挙型)とは、複数の定数をひとつにまとめておくことができる型のこと。
Enumで定義する定数のことを列挙子と呼ぶ。

public class Main {

    public static void main(String[] args) {
        Fruit fruit_type = Fruit.Orange;

        System.out.println(fruit_type);
    }

    protected enum Fruit {
        Orange,
        Apple,
        Melon
    };

}
実行結果
Orange

Elvis Presley

偉大なるロックンローラー
私は「A Little Less Conversation」が好きです
https://www.youtube.com/watch?v=Zx1_6F-nCaw

Elvis has left the Building.

往年の人気歌手エルビス・プレスリーの有名なエピソードにまつわる表現です。
プレスリーのコンサートが終わっても、アンコールを期待してなかなか帰ろうとしない聴衆に向かって「エルビスはもうこの建物を出ました」とアナウンスを流して、聴衆が会場から去るよう促したことが始まりです。

現在は、どのようなイベントについても、終了したことについて使われます。

サンプルコード

1.5より前でのシングルトンの作り方その1

コンストラクタをpriavteにして、クラスの利用者がそのクラスの唯一のインスタンスにアクセスできるようにpublic staticのメンバを提供している。

privateのコンストラクタは、public static finalのフィールドであるElvis.INSTANCEを初期化するために1度だけ呼ばれる。
これでElvisが世界に一人しかいないことが保証される。

例1

//public finalのフィールドによるシングルトン
public class Elvis{
    public static final Elvis INSTANCE = new Elvis();
    private Elvis() { ... }

    public void leaveTheBuliding() { ... }

}

1.5より前でのシングルトンの作り方その2

その1のメンバをpublic staticにするのが2つ目の方法。
Elvis.getInstance()でオブジェクト参照を返す。
この良いところは宣言によりそのクラスがシングルトンになっていることが明白であること。

例2

//staticファクトリーメソッドによるシングルトン
public class Elvis{
    private static final Elvis INSTANCE = new Elvis();
    private Elvis() { ... }
    public static Elvis getInstance() { return INSTANCE; }

    public void leaveTheBuilding() { ... }
}

でも、例1、例2の方法で作られたElvisには偽物が存在する可能性があって、それを防ぐには以下のようなメソッドを追加する必要がある。

例3

//シングルトン特性を保持するためのreadResolveメソッド
private Object readResolve() throws ObjectStreamException{
    /*
     * 本物のElvisを返して、Elvisの偽物をガーベジコレクタに
     * 始末させる。
     * 
     */
    return INSTANCE;
}

最新の一番良い方法

Java 1.5からできるようになった3つ目の方法。
単一要素をもつenum型を単純に作るだけ。
簡単な記述だし偽物を許さない鉄壁さもあるからシングルトンを作るならこのやり方にしましょう、だって。

例4

// enumシングルトン - 好ましい方法
public enum Elvis {
    INSTANCE;

    public void leaveTheBuilding() { ... }
}

続く

【Effective Javaを読む】 第2章 項目4 『privateのコンストラクタでインスタンス化不可能を強制する』
https://qiita.com/Natsukii/items/661b645482d814b73914

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1