싱글턴 패턴의 구현 및 파괴 방식

싱글턴 패턴은 애플리케이션 내에서 단 하나의 인스턴스만 생성되도록 하는 디자인 패턴입니다. 이 글에서는 싱글턴 패턴의 구현 방법과 이를 파괴할 수 있는 다양한 방법에 대해 다룹니다.

먼저, 가장 기본적인 싱글턴 패턴의 구현을 살펴보겠습니다.

import java.io.Serializable;
import java.lang.reflect.Constructor;

public class UniqueInstance implements Cloneable, Serializable {
    private static volatile UniqueInstance instance;

    private UniqueInstance() {
        if (instance != null) {
            throw new RuntimeException("이미 인스턴스가 생성되었습니다.");
        }
    }

    public static UniqueInstance getInstance() {
        if (instance == null) {
            synchronized (UniqueInstance.class) {
                if (instance == null) {
                    instance = new UniqueInstance();
                }
            }
        }
        return instance;
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        throw new CloneNotSupportedException();
    }

    private Object readResolve() {
        return getInstance();
    }
}

위 코드는 싱글턴 패턴의 인스턴스를 생성하고, 복제와 직렬화를 통한 인스턴스 생성을 막아줍니다.

다음은 싱글턴 패턴을 파괴하는 방법들을 테스트하는 코드들입니다.

클론을 이용한 파괴 시도

public class CloneTest {
    public static void main(String[] args) {
        try {
            UniqueInstance uniqueInstance1 = UniqueInstance.getInstance();
            UniqueInstance uniqueInstance2 = (UniqueInstance) uniqueInstance1.clone();
            System.out.println(uniqueInstance1.hashCode());
            System.out.println(uniqueInstance2.hashCode());
            System.out.println(uniqueInstance1 == uniqueInstance2);
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
    }
}

직렬화와 역직렬화를 이용한 파괴 시도

import java.io.*;

public class SerializationTest {
    public static void main(String[] args) {
        try {
            UniqueInstance uniqueInstance1 = UniqueInstance.getInstance();
            FileOutputStream fos = new FileOutputStream("uniqueInstance.ser");
            ObjectOutputStream oos = new ObjectOutputStream(fos);
            oos.writeObject(uniqueInstance1);

            FileInputStream fis = new FileInputStream("uniqueInstance.ser");
            ObjectInputStream ois = new ObjectInputStream(fis);
            UniqueInstance uniqueInstance2 = (UniqueInstance) ois.readObject();

            System.out.println(uniqueInstance1.hashCode());
            System.out.println(uniqueInstance2.hashCode());
            System.out.println(uniqueInstance1 == uniqueInstance2);
        } catch (IOException | ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}

리플렉션을 이용한 파괴 시도

import java.lang.reflect.Constructor;

public class ReflectionTest {
    public static void main(String[] args) {
        try {
            UniqueInstance uniqueInstance1 = UniqueInstance.getInstance();
            Constructor<UniqueInstance> constructor = UniqueInstance.class.getDeclaredConstructor();
            constructor.setAccessible(true);
            UniqueInstance uniqueInstance2 = constructor.newInstance();

            System.out.println(uniqueInstance1.hashCode());
            System.out.println(uniqueInstance2.hashCode());
            System.out.println(uniqueInstance1 == uniqueInstance2);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

위 코드들은 각각 클론, 직렬화/역직렬화, 리플렉션을 통해 싱글턴 패턴을 파괴하려는 시도를 보여줍니다. 그러나 UniqueInstance 클래스의 구현으로 인해 이러한 시도들은 모두 실패하게 됩니다.

태그: 싱글턴 디자인패턴 클론 직렬화 리플렉션

10월 6일 19:02에 게시됨