Javaのstaticファクトリメソッドを使用するメリット

Javaのstaticファクトリメソッドとは

Javaのstaticファクトリメソッド(static factory method)は、クラスのインスタンスを生成するための静的メソッドです。
通常のコンストラクタの代わりに使用されることが多く、特定の条件や論理に基づいてオブジェクトを作成するのに役立ちます。
staticファクトリメソッドには以下のような利点があります:

1. 名前を付けられる:
コンストラクタとは異なり、staticファクトリメソッドには名前を付けることができます。
これにより、メソッドの意図を明確にすることができます。
実装例

public class Person {
    private String name;
    private int age;

    // プライベートコンストラクタ
    private Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    // コンストラクタとは別名のメソッド
    public static Person createPerson(String name, int age) {
        return new Person(name, age);
    }
}

2. キャッシュや再利用:
メソッド内で作成したインスタンスをキャッシュし、次回以降の呼び出しで再利用することができます。
これにより、性能の向上やメモリ使用量の削減が可能です。
実装例

// スーパークラス
class Animal {
    private String name;

    protected Animal(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    // キャッシュ用のMap
    private static final Map<String, Animal> cache = new HashMap<>();

    // staticファクトリメソッド
    public static Animal createAnimal(String type, String name) {
        // typeごとにキャッシュ化しておく
        if (cache.containsKey(type)) {
            // cacheのキーにtypeがあれば、そのインスタンスを返す
            return cache.get(type);
        }
        animal = new Dog(name);

        // typeをキーにインスタンス化されたオブジェクトを格納
        cache.put(key, animal);
        return animal;
    }
}

// サブクラス
class Dog extends Animal {
    public Dog(String name) {
        super(name);
    }
}

3. サブクラスのインスタンスを返せる:
staticファクトリメソッドは、インスタンス化するクラスのサブクラスのインスタンスを返すことができます。
これにより、柔軟な設計が可能です。
実装例

// スーパークラス
class Animal {
    private String name;

    protected Animal(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    // staticファクトリメソッド
    public static Animal createAnimal(String type, String name) {
        // typeの値に応じてサブクラスのいずれかを返す
        if (type.equalsIgnoreCase("dog")) {
            return new Dog(name);
        } else if (type.equalsIgnoreCase("cat")) {
            return new Cat(name);
        } else {
            throw new IllegalArgumentException("Unknown animal type");
        }
    }
}

// サブクラス
class Dog extends Animal {
    public Dog(String name) {
        super(name);
    }
}

// サブクラス
class Cat extends Animal {
    public Cat(String name) {
        super(name);
    }
}

4. インスタンスの個数を制御できる:
必要に応じて、特定のクラスのインスタンスが常に1つだけであることを保証したり、他の特定の制約を適用することができます。

public class Person {
    private String name;
    private int age;
    // 最大インスタンス数
    private static final int MAX_INSTANCES = 2;
    private static final List<Person> instances = new ArrayList<>();

    // プライベートコンストラクタ
    private Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    // コンストラクタとは別名のメソッド
    public static Person createPerson(String name, int age) {
        // 最大値に達していなければインスタンスを生成する
        if (instances.size() < MAX_INSTANCES) {
            Person person = new Person(name, age);
            instances.add(person);
            return person;
        } else {
            // 既存のインスタンスを再利用
            return instances.get(instances.size() % MAX_INSTANCES);
        }
    }
}

staticファクトリメソッドにはいろいろ使い方があり、シチュエーションによっては便利ですね。
状況に応じて使い分けましょう。