0
0

More than 1 year has passed since last update.

Java の enum Singleton が「キモい」と言われたので隠蔽してみた

Posted at

概要

Animal animal = Dog.INSTANCEDog.INSTANCEを隠蔽する試作 4 つ

1. enum をパッケージプライベートにする

実装

Dog.java
package animal;

enum Dog implements Animal {
    INSTANCE
}
Animal.java
package animal;

public interface Animal {
    static Animal getDog() {
        return Dog.INSTANCE;
    }
}

備考

  • インスタンスの取得: Animal animal = Animal.getDog()
  • Animal.getDog() instanceof Dog: コンパイルエラー

2. enum をクラスの内部クラスにする

実装

Cat.java
import animal.Animal;

public class Cat {
    private enum CatImpl implements Animal {
        INSTANCE
    }

    public static Animal getInstance() {
        return CatImpl.INSTANCE;
    }

    private Cat() {
    }
}

備考

  • インスタンスの取得: Animal animal = Cat.getInstance()
  • Cat.getInstance() instanceof Cat: false

3. enum をインタフェースの内部クラスにする

実装

Bird.java
import animal.Animal;

public interface Bird extends Animal {
    class Cage {
        private enum BirdImpl implements Bird {
            INSTANCE
        }

        private Cage() {
        }
    }

    static Bird getInstance() {
        return Cage.BirdImpl.INSTANCE;
    }
}

備考

  • インスタンスの取得: Bird bird = Bird.getInstance()
  • Bird.getInstance() instanceof Bird: true
  • Bird インタフェースの実装クラスは無数に定義できるので Bird 型のインスタンスは 1 つではない

4. 3 のインスタンスを 1 つに制限する

実装

Fox.java
package fox;

import animal.Animal;

public sealed interface Fox extends Animal permits FoxImpl {
    static Fox getInstance() {
        return FoxImpl.INSTANCE;
    }
}

enum FoxImpl implements Fox {
    INSTANCE
}

備考

  • インスタンスの取得: Fox fox = Fox.getInstance()
  • Fox.getInstance() instanceof Fox: true
  • Fox 型インスタンスは FoxImpl のインスタンス 1 つのみ

実行結果

Main.java
import animal.Animal;
import fox.Fox;

public class Main {
    public static void main(String[] args) {
        Animal dog = Animal.getDog();

        System.out.print("dog.getClass(): ");
        System.out.println(dog.getClass());

        System.out.print("dog instanceof Animal: ");
        System.out.println(dog instanceof Animal);

        // System.out.println(dog instanceof Dog);

        System.out.println();

        Animal cat = Cat.getInstance();

        System.out.print("cat.getClass(): ");
        System.out.println(cat.getClass());

        System.out.print("cat instanceof Animal: ");
        System.out.println(cat instanceof Animal);

        System.out.print("cat instanceof Cat: ");
        System.out.println(cat instanceof Cat);

        System.out.println();

        Bird bird = Bird.getInstance();

        System.out.print("bird.getClass(): ");
        System.out.println(bird.getClass());

        System.out.print("bird instanceof Animal: ");
        System.out.println(bird instanceof Animal);

        System.out.print("bird instanceof Bird: ");
        System.out.println(bird instanceof Bird);

        System.out.println();

        Fox fox = Fox.getInstance();

        System.out.print("fox.getClass(): ");
        System.out.println(fox.getClass());

        System.out.print("fox instanceof Animal: ");
        System.out.println(fox instanceof Animal);

        System.out.print("fox instanceof Fox: ");
        System.out.println(fox instanceof Fox);
    }
}
標準出力
dog.getClass(): class animal.Dog
dog instanceof Animal: true

cat.getClass(): class Cat$CatImpl
cat instanceof Animal: true
cat instanceof Cat: false

bird.getClass(): class Bird$Cage$BirdImpl
bird instanceof Animal: true
bird instanceof Bird: true

fox.getClass(): class fox.FoxImpl
fox instanceof Animal: true
fox instanceof Fox: true

参考文献

Effective Java 第 3 版

  • 項目 1 コンストラクタの代わりに static ファクトリメソッドを検討する

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

【付録 A】 enum Singleton に直接ファクトリメソッドを作る

実装

Singleton.java
public enum Singleton {
    INSTANCE;

    public static Singleton getInstance() {
        return INSTANCE;
    }
}

備考

  • インスタンスの取得: Singleton singleton = Singleton.getInstance()
    ただし、Singleton singleton = Singleton.INSTANCEも可

【付録 B】 全ソースコード

0
0
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
0