본문 바로가기
SPRING

[파트 1. 스프링 입문] 챕터 2-2. 싱글톤 패턴

by ZZON90 2022. 3. 14.

 디자인 패턴 중 하나인 싱글톤 패턴에 대해 포스팅합니다.

 

 

싱글톤 패턴이란?

 싱글톤 패턴은 어떠한 클래스(객체)가 유일하게 1개만 존재할 경우 사용합니다. 이를 주로 사용하는 경우는 여러 클래스(객체)가 서로 자원을 공유할 때 사용합니다. 현실 세계에서는 프린터를 예로 들 수 있으며, 실제 프로그래밍에서는 TCP Socket 통신에서 서버와 연결된 Connect 객체에 주로 사용합니다.

 Spring에서는 Bean이라고 불리는 객체가 싱글톤으로 관리됩니다. Bean은 개발자가 직접 생성하지 않고 ApplicatinContext을 통해서 Spring에서 관리하게 됩니다. 싱글톤 패턴은 기본적으로 default 생성자를 private으로 막고 getInstance라는 메서드를 통해 생성되어 있는 객체를 리턴하거나 생성되지 않은 경우 객체를 생성하여 리턴합니다. 이로 인해 어떠한 클래스에서도 getInstance라는 메서드를 사용했을 때 동일한 객체를 얻을 수 있도록 보장합니다.

 

 

예제

 싱글톤 패턴 설명시 주로 사용되는 SocketClient를 통해 설명합니다.

 

SocketClient 클래스

public class SocketClinet{
	private static SocketClient socketClient = null;
    
    private SocketClient(){
    	// 생략
    }
    
    public static SoketClient getInstance(){
    	if(socketClient==null){
        	soketClient = new SocketClient();
        }
        
        return socketClient;
    }
    
    public void connect(){
    	System.out.println("connect");
    }
}

 SocketClient 클래스가 있다고 가정합니다. 이때, 기본 생성자인 SocketClient()는 접근제어자를 private으로 하여 외부에서 접근하지 못하도록 제어합니다. 그리고 getInstance를 통해 생성자가 null인지 체크한 후 null일 경우에는 새로 생성하고 이미 생성된 경우에는 객체를 리턴합니다. getInstance는 static 메서드로 만들어 객체를 생성하지 않고 클래스에 바로 접근할 수 있도록 합니다. socketClient 변수도 static으로 설정하여 객체가 최초에 하나만 만들어질 수 있도록 합니다.

 

AClazz, BClazz 클래스

public class AClazz{
	private SocketClient socektClient;
    
    public AClazz(){
    	// 기본생성자를 막았기 때문에 생성자 사용 불가.
    	// this.socketClient = new SocketClient();
        
        this.socketClient = SocketClient.getInstance();
    }
    
    public SocketClient getSocektClient(){
    	return this.socketClient;
    }
}

public class BClazz{
	private SocketClient socektClient;
    
    public BClazz(){       
        this.socketClient = SocketClient.getInstance();
    }
    
    public SocketClient getSocektClient(){
    	return this.socketClient;
    }
}

 AClazz에서 기본생성자를 사용하여 SocketClient.getInstance()를 호출합니다. getInstance를 통해 리턴된 객체를 socketClient에 대입합니다. BClazz 역시 동일한 로직으로 구성합니다.

 

Main 클래스

public class Main{
	public static void main(String args[]){
    	Aclazz aClazz = new AClazz();
        Bclazz bClazz = new BClazz();
        
        SocketClient aClient = aClazz.getSocketClient();
        SocketClient bClient = bClazz.getSocketClient();
        
        System.out.println("두개의 객체가 동일한가?");
        System.out.println(aClient.equals(bClient));
    }
}

 Main 클래스에서 Aclazz를 생성합니다. BClazz도 생성합니다. aClient에 aClazz의 getSocektClient 메서드를 호출하고 bClient에도 bClazz의 getSocketClient를 호출합니다. aClient와 bClient는 과정은 다르지만 결국 동일한 객체를 얻게 됩니다.

 AClazz 생성자 호출 시 SocketClient의 getInstance를 호출하므로 socketClient는 null입니다. 때문에 처음 객체를 생성하고 생성된 객체를 리턴합니다. BClazz 생성자 호출 시 SocketClient의 getInstance를 호출하므로 socketClient가 null인지 체크합니다. 이미 생성된 객체이기 때문에 socketClient를 리턴합니다.

 결국 두 Clazz의 getSocketClient 메서드를 호출하면 동일한 객체가 리턴되게 됩니다.

댓글