Java/고급객체지향

고급객체지향 프로그래밍 - 싱글턴 패턴(Singleton Pattern), 반복자 패턴(Iterator Pattern)

얄루몬 2021. 10. 19. 16:04

싱글턴 패턴(Singleton Pattern)

 

싱글턴 패턴이란?

싱글턴 패턴(Singleton pattern)을 따르는 클래스는, 생성자가 여러 차례 호출되더라도 실제로 생성되는 객체는 하나이고 최초 생성 이후에 호출된 생성자는 최초의 생성자가 생성한 객체를 리턴한다. 이와 같은 디자인 유형을 싱글턴 패턴이라고 한다. 주로 공통된 객체를 여러개 생성해서 사용하는 DBCP(DataBase Connection Pool)와 같은 상황에서 많이 사용된다.

 

 

싱글턴 패턴의 목적

- 클래스가 한 개의 인스턴스(객체)만을 만들 수 있도록하고, 어디서나 생성된 인스턴스에 접근할 수 있도록 하기 위함이다.

 

싱글턴 패턴의 요소

요소 설명
이름 싱글턴(Singleton)
문제 여러 객체가 생성되면 상태 관리가 어려움
해결 방안 객체 생성자를 중앙 관리한다.
결과 객체가 1개라서 일관된 상태가 유지된다.

 

고전적 싱글턴 패턴 구현법

- private 디폴트 생성자 구현

- 싱글턴 인스턴스를 저장하는 정적 멤버 변수 생성

- 싱글턴 인스턴스를 반환하는 정적 팩토리 메소드 구현

>>문제점:  멀티쓰레드를 사용하는 프로그램에서는 문제가 될 수 있다.

public class Singleton{
	// 유일한 인스턴스를 저장 클래스 변수이기 때문에 객체 생성 없이도 바로 사용 가능하다. 
    private static Singleton uniqueInstance;
    //기타 멤버 변수
    private Singleton(){ }
    
    public static Singleton getInstance(){
		if(uniqueInstance == null){
        	//NULL이 아니면 return으로 바로 가서 객체 생성을 하지 않음
        	uniqueInstance = new Singleton(); 
        }
   		return uniqueInstance;
    }
	//기타 메소드
}

출처: http://preview.kyobobook.co.kr/preview/008/epb/286/4801160501286/images/EE_028.jpg

 

Thread - safe 버전의 싱글턴 

고전적인 방법의 싱글턴 패턴은 다중 쓰레드에서 사용하면 문제가 생기게 된다. (다중 쓰레드란 쉽게 CPU를 나눠 쓰는 것을 의미한다.)

//Thread - safe 버전의 싱글턴 

public class Singleton {
	private static Singleton uniqueInstance;
    
    private Singleton(){ } 
    public static synchronized Singleton getInstance(){
    	if(uniqueInstanc == null){
        	uniqueInstance = new Singleton();
        }
    	return uniqueInstance
    }
}

- 여러 개의 스레드에서는 앞에 작성된 고전 싱글턴 패턴 코드를 사용하면 문제가 발생할 수 있다. 이를 해결하려면 getinstance() 함수에 동기화 시키는 코드를 넣어주어야 한다. (synchronized)


- 비효율적(느려지는 문제)일 수 있기에 이를 해결하기 위해서는 getinstance()의 속도가 크게 영향을 미칠 정도가 아니라면 그냥 두거나, 인스턴스를 필요할 때 생성하지 않고, 프로그램이 시작될 때 생성해준다.

//다중 스레드 상황에서 느려지는 문제를 해결하기 위해 인스턴스를 프로그램 시작될 때 생성하는 코드

public class Singleton {
	private static Singleton inst = new Singleton();
    private Singleton(){ }
    public static Singleton getInstance() { 
    	return inst;
    }
    //나머지 멤버 함수 코드
}

- DCL(Double - checking Locking)을 사용해서 getInstance()함수에서 동기화 되는 부분을 줄이는 방법

public class Singleton {
	private volatile static Singleton inst;
    private Singleton(){ }
    public static Singleton getInstance(){
    if (inst == null){
    	synchronized (Singleton.class){
        	inst = new Singleton();
            	}
    		}
    	}
    return inst;
	}	
    //나머지 멤버 함수 코드
}

>> votaile

- 변수를 CPU 캐쉬에 저장하지 않고 메모링서 읽고 저장한다.

- 쓰레드를 사용할 떄 다른 프로세서에 있는 캐쉬에서 변수값이 저장되어 서로 다른 값을 사용하는 것을 방지한다.

 

>> synchronized

- 여러 쓰레드에서 사용하려고 할 때 Locking 

 

- 내부 정적 클래스 사용

public class Singleton{
	private static class InnerSingleton{
    	static final Singleton inst = new Singleton();
    }
    private Singleton() { }
    public static Singleton getInstance(){
    	return InnerSingleton.inst;
    }
}

 

 


 

반복자 패턴(Iterator Pattern)

 

 

반복자 패턴이란?

반복자 패턴(iterator pattern)은 객체 지향 프로그래밍에서 반복자를 사용하여 컨테이너를 가로지르며 컨테이너의 요소들에 접근하는 디자인 패턴이다. 반복자 패턴은 컨테이너로부터 알고리즘을 분리시키며, 일부의 경우 알고리즘들은 필수적으로 컨테이너에 특화되어 있기 때문에 분리가 불가능하다.
이를테면, SearchForElement라는 가설적 알고리즘은 일반적으로 컨테이너에 특화된 알고리즘으로서 구현하지 않고 반복자 유형을 사용하여 구현할 수 있다. 이는 필요한 반복자 유형을 지원하는 컨테이너에 SearchForElement를 사용할 수 있게 한다.

 

반복자 패턴의 목적

- 요소(배열, 리스트, 트리, 맵 등의 여러 자료구조)를 담고 있는 객체 내부 구조에 대한 이해없이 각 요소를 순서대로 접근하고 사용할 수 있도록 방법을 제공하는 것이 목적이다.

 

- 자료구조가 다르면 반복문을 사용할 때 접근하는 방식이 달라지는데 반복자 패턴을 사용하면 코드변경을 최소화시켜 반복문대신 사용할 수 있다. 

 

요소 설명
이름 반복자(Iterator)
문제 자료 구조 클래스의 요소를 한 개씩 접근하는 API가 서로 다르다
해결 방안 반복자 객체를 중간에 넣는다.
결과 변경 최소화

 

반복자에서 사용되는 함수

함수 설명
iterator() 반복자에 대한 참조(iterator 자료형)를 반환
hasNext() 요소가 더 존재하는지 확인.
True 또는 False를 반환
next() 다음 요소를 가져오기. 
Object를 반환하기 때문에 변환해서 사용