오직 객체의 인스턴스를 1개만 생성하는 것
객체의 인스턴스를 1개만 생성하는 것? 언듯 보기에는 단순해 보인다. 그러니 예제 코드로 직접 확인해 보자.
가장 간단하게 싱글톤 예제를 만들어보자
//간단한 싱글톤 예제
public class SingletonService {
//1.static 영역에 객체를 1개만 생성해둠.
private static final SingletonService instance = new SingletonService();
//2.public 으로 열어 외부에서 이 객체가 필요하면 조회할 수 있도록 허용.
public static SingletonService getInstance() {
return instance;
}
//3. **생성자를 private 로 선언하여 외부에서 new 객체 를 할 수 없도록 막아둠.<주의 해야함>**
private SingletonService() {
}
public void logic(){
System.out.println("싱글톤 객체의 로직 메서드 호출");
}
}
만약 외부에서 SingletonService 의 logic() 부분을 작동시키려면 static으로 미리 깔아둔 instance를 getInstance()를 통해 접근해야만한다. 또한 나중에 logic()을 호출하면 이 역시 getInstance()를 통해 이전에 깔아둔 instance 에 접근을 하면된다.
즉 static을 통해 해당 인스턴스를 여러번 호출 하여도 같은 인스턴스가 호출이 된다.
→ 정말 그런지 테스트 코드를 돌려보자!
class SingletonTest {
@Test
@DisplayName("싱글톤 패턴을 적용한 객체 사용")
void singletonServiceTest() {
SingletonService singletonService1 = SingletonService.getInstance();
SingletonService singletonService2 = SingletonService.getInstance();
System.out.println("singletonService1 = " + singletonService1);
System.out.println("singletonService2 = " + singletonService2);
assertThat(singletonService1).isSameAs(singletonService2);
}
}
빌드를 해보면
다음과 같은 결과를 확인 할 수 있다.
같은 객체가 불러와 지는 것을 확인 할 수 있다.
여담으로 isSameAs()와 isEqulTo()에 설명하자면
isSameAs()는 == 과 같은 논리(메모리상 같은 객체인지)로 대상을 비교 하고
isEqulTo()는 객체에 오버라이드된, 혹은 object에 기본으로 깔리는 Equls()를 기반으로 대상을 비교한다.
등 여라가지 문제가 있다.
결과적으로 싱글톤 패턴을 사용하면 프로그램 자체의 유연성이 떨어지게 된다.
이는 객체지향이 지향하는 바와 많이 동떨어지게 된다.
단순히 보면 싱글톤 패턴은 장점보다는 단점이 많기 때문에 사용하면 안될 패턴 처럼 보인다. 하지만 메모리와 시간의 측면에서의 장점을 무시할 수는 없다.
개인적으로 그동안 프로그래밍을 공부하면서 느낀것은 “결국 상황에 따라 어떠한 개념을 적용할지 말지는 다르다” 는 것이다. 싱글톤 패턴의 장점을 이용하기 위해 단점을 감수할 수있다면 써도 괜찮다고 생각한다. 혹은 그 반대의 경우에도 명분만 있다면 괜찮다 생각한다.
결국 장점을 챙기면 그만큼 잃은 것이 있다.