싱글톤 패턴

이강용·2024년 2월 1일
0

CS

목록 보기
14/109

싱글톤 패턴(Singleton Pattern)은 무엇인가?

  • 클래스의 인스턴스가 오직 하나만 생성되도록 보장하고, 그 인스턴스에 대한 전역 접근점을 제공하는 패턴. 즉, 싱글톤 패턴을 사용하면, 해당 클래스의 인스턴스는 애플리케이션 전반에 걸쳐 하나만 존재하게 됨

싱글톤 패턴의 목적과 특징

  1. 유일한 인스턴스 보장 : 클래스의 인스턴스가 하나만 생성되고, 어디서든 그 인스턴스에 접근할 수 있도록함
  2. 전역 접근점 제공 : 생성된 인스턴스에 대한 전역 접근점을 제공하여, 어디서든 이 인스턴스를 사용할 수 있게 함
  3. 자원 관리 : 특정 클래스에 대한 인스턴스가 하나만 필요한 경우(예: DB연결, 파일 시스템 등)에 효율적인 자원 관리를 도움
public class Singleton {
    private static Singleton instance;
    
    // 생성자를 private으로 선언하여 외부에서의 인스턴스화를 방지
    private Singleton() {}
    
    // 인스턴스에 접근하기 위한 전역 접근점
    public static Singleton getInstance() {
        if (instance == null) { // 인스턴스가 아직 생성되지 않았을 경우에만 생성
            instance = new Singleton();
        }
        return instance;
    }
}

장점

  • 싱글톤 패턴은 DB, Network, FileSystem 등의 I/O Bound 자원을 관리하는데 특히 유용함. 이러한 자원들은 시스템의 성능에 상당한 영향을 미치며, 동시에 여러 접근이 발생할 경우 성능 저하나 불필요한 자원 소모를 일으킬 수 있음.

DB(Database)

  • 문제 : DB 연결은 매우 비용이 많이 드는 작업임. 불필요하게 여러 DB 연결을 생성하면 메모리 사용량이 증가하고, 네트워크 트래픽이 증가하여, 전반적인 성능이 저하될 수 있음
  • 싱글톤의 적용 : DB 연결 인스턴스를 싱글톤으로 관리함으로써, 애플리케이션에서 단 하나의 DB 연결만 유지되고 재사용됨. 이렇게 하면 자원 사용이 최적화되고, 성능이 향상됨

👏🏻 만약, DB에 동시에 100개의 요청이 들어온다면?

  1. 싱글톤 패턴과 DB 연결 풀
  • 싱글톤 패턴은 DB 연결 풀 자체를 애플리케이션 전역에서 단 하나만 생성하고 관리하도록 함. 이렇게 하면 DB 연결 풀 인스턴스가 중복 생성되는 것을 방지하고, 애플리케이션 어디서든 같은 연결 풀 인스턴스에 접근할 수 있음
  • DB 연결 풀은 미리 정래진 수의 DB 연결을 생성하고, 이 연결들을 풀(Pool)에 보관함. 풀에 있는 연결은 필요에 따라 요청을 처리하고, 요청이 완료된 후에는 다시 풀로 반환되어 재사용됨
  1. 동시 요청 처리 과정

    1. 요청 수신 : 백엔드 시스템이 동시에 100개의 요청을 받음
    2. 연결 풀에서 연결 획득 : 각 요청에 대해, 연결 풀에서 사용 가능한(DB와 연결된) 연결을 하나씩 획득함. 연결 풀의 크기가 충분하면, 요청마다 즉시 연결을 할당받을 수 있음
    3. DB 작업 실행 : 할당받은 연결을 사용하여 각 요청에 해당하는 DB 작업(쿼리 등)을 실행함
    4. 연결 반환 : DB 작업이 완료되면, 사용했던 연결을 연결 풀로 반환, 반환된 연결은 다시 사용 가능한 상태가 되며, 다른 요청에서 재사용 될 수 있음
  2. 연결 풀의 관리

  • 연결 풀의 크기 : 연결 풀의 크기는 사전에 설정되며, 이 크기는 동시에 처리할 수 있는 최대 요청 수를 결정함. 예를 들어, 연결 풀의 크기가 100이면 동시에 최대 100개의 DB 연결을 관리할 수 있음
  • 연결 풀의 효율성 : 연결 풀을 사용하면 연결의 생성과 소멸에 드는 비용을 줄일 수 있으며, 연결을 효율적으로 재사용할 수 있음. 이는 시스템의 성능과 자원 사용 효율성을 향상시킴

Network

  • 문제 : 네트워크 연결, 특히 원격 서비스나 API에 대한 연결은 비용이 많이 들고, 연결을 설정하고 해제하는데 시간이 걸림
  • 싱글톤의 적용 : 네트워크 연결 또는 HTTP 클라이언트 인스턴스를 싱글톤으로 관리하면, 연결 오버헤드를 줄이고 효율적으로 네트워크 리소스를 사용할 수 있음

FileSystem I/O

  • 문제 : 파일 시스템 작업은 디스크 I/O에 의존하기 때문에 비용이 많이 들며, 동시에 여러 파일 작업이 이루어질 때 성능 저하를 일으킬 수 있음
  • 싱글톤의 적용 : 파일 시스템 접근자 또는 I/O 관리자를 싱글톤으로 구현함으로써, 파일 작업을 안정적이고 효율적으로 관리할 수 있음. 동시 접근 제어나 캐싱 전략을 통합 관리할 수 있는 장점도 있음

싱글톤 패턴 - Java

class Singleton {
	private static class singleInstanceHolder {
		private static final Singleton INSTANCE = new Singleton(); 
	}
	public static Singleton getInstance() { 
    	return singleInstanceHolder.INSTANCE;
	} 
}	
public class HelloWorld{
	public static void main(String []args){
		Singleton a = Singleton.getInstance(); 
        Singleton b = Singleton.getInstance(); 	
        System.out.println(a.hashCode()); 
        System.out.println(b.hashCode());
		if (a == b){ 
        	System.out.println(true);
		} 
	}
}

단점

  • 의존성이 높아지며 TDD(Test Driven Development)를 할 때 걸림돌이 됨. TDD를 할 때 단위 테스트를 주로 하는데, 단위 테스트는 테스트가 서로 독립적이어야 하며 테스트를 어떤 순서로든 실행할 수 있어야 함
    하지만, 싱글톤 패턴은 미리 생성된 하나의 인스턴스를 기반으로 구현하는 패턴이므로 각 테스트 마다 독립적인 인스턴스를 만들기가 어려움

mocha 라이브러리로 테스트 하기

const assert = require("assert");
const a = [1, 2, 3];
describe("Array", function () {
  describe("#indexOf()", function () {
    it("should return -1 when the value is not present", function () {
      assert.equal(a.indexOf(4), -1);
      a[0] = 4;
    });
  });
  describe("#indexOf()", function () {
    it("should return -1 when the value is not present", function () {
      assert.equal(a.indexOf(4), -1);
    });
  });
});

위, 아래 로직 순서를 바꾸고 npm test 실행

const assert = require("assert");
const a = [1, 2, 3];
describe("Array", function () {
  describe("#indexOf()", function () {
    it("should return -1 when the value is not present", function () {
      assert.equal(a.indexOf(4), -1);
    });
  });
  describe("#indexOf()", function () {
    it("should return -1 when the value is not present", function () {
      assert.equal(a.indexOf(4), -1);
      a[0] = 4;
    });
  });
});

  • 위의 두 예시는 싱글톤 패턴의 인스턴스는 아니지만 테스트 중에 공유 상태를 변경하는 것이 후속 테스트에 미치는 영향을 잘 보여주는 예이다.
  • 테스트 케이스들이 공유 상태에 의존하게 되면, 한 테스트의 실행 결과가 다른 테스트에 영향을 미치게 된다. 이는 싱글톤 인스턴스에서도 비슷하게 나타날 수 있는데, 싱글톤 인스턴스가 변경된 상태를 유지하므로 각 테스트가 독립적으로 실행되지 않고 이전 테스트의 상태에 영향을 받을 수 잇기 때문이다.
  • 따라서, 테스트 간의 결합도를 낮추고 독립성을 유지하는 것이 중요하며 테스트 케이스를 작성할 때, 각 테스트가 격리되어야 하고, 다른 테스트에 의존하지 않아야 한다
profile
HW + SW = 1

0개의 댓글