PersonSingleton.java

package fr.univtln.bruno.samples.java101.tp1.factory;

/**
 * Simple educational singleton that holds person attributes directly.
 *
 * <p>This class demonstrates a configurable singleton pattern using the
 * initialization-on-demand idiom (double-checked locking variant here to
 * allow explicit parameterized initialization).</p>
 *
 * Usage examples:
 * <pre>
 *   // Option A: provide parameters explicitly once before first use
 *   PersonSingleton.initialize("Alice", "Smith", 28);
 *   PersonSingleton p = PersonSingleton.getInstance();
 *
 *   // Option B: use the default instance (created on first access)
 *   PersonSingleton p2 = PersonSingleton.getInstance();
 * </pre>
 *
 * Notes for students:
 * - Call {@link #initialize(String,String,int)} only once before first use if you
 *   want custom values; subsequent calls have no effect and return the existing
 *   instance.
 * - The implementation is thread-safe and lazy: the instance is created only when
 *   needed.
 */
public final class PersonSingleton {

    // Embedded person attributes (example shared resource)
    private final String firstName;
    private final String lastName;
    private final int age;

    // Volatile singleton instance for double-checked locking
    private static volatile PersonSingleton INSTANCE;

    // Private constructor prevents external instantiation
    private PersonSingleton(String firstName, String lastName, int age) {
        this.firstName = firstName;
        this.lastName = lastName;
        this.age = age;
    }

    /**
     * Initialize the singleton with the provided parameters. If the singleton has
     * already been created, this call has no effect and the existing instance is
     * returned.
     *
     * @param firstName person's first name (non-null)
     * @param lastName person's last name (non-null)
     * @param age person's age (non-negative)
     * @return the singleton instance
     * @throws NullPointerException if firstName or lastName is null
     * @throws IllegalArgumentException if age is negative
     */
    public static PersonSingleton initialize(String firstName, String lastName, int age) {
        if (firstName == null) throw new NullPointerException("firstName must not be null");
        if (lastName == null) throw new NullPointerException("lastName must not be null");
        if (age < 0) throw new IllegalArgumentException("age must not be negative");

        if (INSTANCE == null) {
            synchronized (PersonSingleton.class) {
                if (INSTANCE == null) {
                    INSTANCE = new PersonSingleton(firstName, lastName, age);
                }
            }
        }
        return INSTANCE;
    }

    /**
     * Return the singleton instance. If it wasn't initialized explicitly, a default
     * instance is created on first access (with conservative example values).
     *
     * @return the singleton instance
     */
    public static PersonSingleton getInstance() {
        if (INSTANCE == null) {
            synchronized (PersonSingleton.class) {
                if (INSTANCE == null) {
                    INSTANCE = new PersonSingleton("John", "Doe", 30);
                }
            }
        }
        return INSTANCE;
    }

    /**
     * Returns the person's first name.
     *
     * @return the person's first name
     */
    public String getFirstName() {
        return firstName;
    }

    /**
     * Returns the person's last name.
     *
     * @return the person's last name
     */
    public String getLastName() {
        return lastName;
    }

    /**
     * Returns the person's age in years.
     *
     * @return the person's age
     */
    public int getAge() {
        return age;
    }

    /**
     * Returns the person's full name (first + space + last).
     *
     * @return the person's full name
     */
    public String getFullName() {
        return firstName + " " + lastName;
    }

    /**
     * Convenience: whether the singleton has been initialized (explicitly or by
     * lazy default initialization).
     *
     * @return true if the singleton instance exists
     */
    public static boolean isInitialized() {
        return INSTANCE != null;
    }

}