-
2. 싱글톤 패턴(Singleton Pattern)DesignPattern 2018. 7. 23. 21:23반응형
두번째 디자인패턴은 싱글톤 패턴!!!
1. 싱글톤 패턴(Singleton Pattern)이란?
- 특정 클래스에 대해 객체 인스턴스를 하나만 만들고 관리하는 패턴입니다.
- 해당 클래스의 하나의 인스턴스가 만들어지고, 어디서든지 하나의 인스턴스에 접근할 수 있도록 하기 위한 패턴입니다.
- 객체 인스턴스를 하나만 만드는 패턴이기에 인스턴스가 두 개 이상이 될 수 없습니다.
- 접근제어자를 통해 다른 어떤 클래스에서도 자신의 인스턴스를 추가하지 못하도록 해야합니다.
2. 싱글톤 패턴 장점
- 정적(static) 클래스 변수와 메소드를 잘 처리할 수 있고, 접근 제어자를 잘 다룰줄 안다면 크게 어렵지 않습니다.
- 객체가 필요할 때 인스턴스를 직접 만드는 것이 아니라 인스턴스를 요청해야 합니다.
- 고정된 메모리 영역을 사용하도록 단 한번 new 연산자로 인스턴스를 얻어오기 때문에 메모리의 낭비를 줄일 수 있습니다.
- 전역변수로 선언되고, 전역메소드로 호출 하기 때문에 다른 클래스에서 사용하기 쉽습니다.
- 공통된 객체를 사용해야하는 코딩에서 매번 객체를 생성하지않고, 같은 객체를 사용하도록 하면 성능면에서 좋아집니다.
3. 싱글톤 패턴의 단점
- 객체 지향의 원칙인 "개방-폐쇄의 원칙"에 위배되는 경우가 많습니다.
* 객제 지향의 원칙은 5가지입니다.
① SRP(Single Responsibility Principle) : 단일 책임의 원칙
- 객체는 오직 하나의 책임을 가져야 한다는 원칙입니다.
② OCP(Open Close Principle) : 개방-폐쇄의 원칙
- 객체는 확장에 대해서는 개방적이고, 수정에 대해서는 폐쇄적이어야 한다는 원칙입니다. ( 객체 기능 확장을 허용하고, 스스로의 변경은 피해야합니다.)
③ LSP : 리스코프 치환의 원칙
- 자식 클래스는 언제나 자신의 부모 클래스를 대체할 수 있다는 원칩니다. ( 부모 클래스자리에 자식 클래스를 넣어도 잘 작동해야 합니다. )
④ ISP : 인터페이스 분리의 원칙
- 클라이언트에서 사용하지 않는 메소드는 사용해서는 안됩니다. 그렇기 때문에 인터페이스를 작게 나누어 만들어야 합니다.
⑤ DIP : 의존성 역전의 원칙
- 추상성이 높고 안정적인 고수준의 클래스는 구체적이고 불안정한 저수준의 클래스에 의존해서는 안된다는 원칙입니다.
- 커플링이 심해지고 수정하기가 어렵습니다.
- 단위 테스트하기가 어려워집니다.
- 가비지 컬렉팅이 되지 않기 때문에 프로그램이 종료될때까지 메모리를 차지합니다.
4. 싱글톤 패턴 실제 사용 예
- 레지스트리 설정이 담긴 객체가 있는데, 그 객체가 여러개라면 혼란스러울 수 있는 경우 싱클톤 패턴을 사용합니다.
- 연결 풀 또는 쓰레드 풀과 같은 자원 풀을 관리하는데 사용합니다.
- DB 커넥션 풀에서 요청에 따른 무분별한 인스턴스 생성하지 않기 위해서 사용합니다.
5. 싱글톤 패턴 방법
▶ priavte static 을 이용해 인스턴스를 만든다. private 접근제어자로 인해 바로 인스턴스로 접근이 불가하고, new 키워드로 생성할 수 없다.
그렇기 때문에 getInstance라는 메소드를 통해 인스턴스에 접근해야 한다.
1) Eagar initalization(심각한 초기화) - 클래스 로딩 시점에 미리 객체를 생성합니다.
- 예외 throw를 할 수 없다.
123456789101112package Singleton;public class Singleton {//eager initialization 전역변수로 인스턴스를 만든다.private static final Singleton singletonInstance = new Singleton();private Singleton() {System.out.println("싱글톤패턴 생성자");}public static Singleton getInstance() {return singletonInstance;}}cs 2) Static block initialization - 클래스 로딩 시점에 미리 객체를 생성하고, 변수 셋팅 및 에러 처리를 위한 구문을 넣습니다.
12345678910111213141516171819package Singleton;public class Singleton {//static block initializationprivate static Singleton singletonInstance;private Singleton() {System.out.println("싱글톤 생성자 생성");}static {try {singletonInstance = new Singleton();} catch(Exception e) {throw new RuntimeException("에러 발생" + e);}}public static Singleton getInstance() {return singletonInstance;}}cs 3) Lazy initialization - 인스턴스가 사용되는 시점에 인스턴스를 만듭니다. Multi Thread 방식에 보장할 수 없습니다.
- Multi Thread 문제를 해결하기 위해 synchronized를 사용합니다. 하지만 getInstance 메소드를 동기화하면 프로그램 느려집니다.
1234567891011121314package Singleton;public class Singleton {private Singleton() {System.out.println("싱글톤 생성자 생성");}public static Singleton getInstance() {if( singletonInstance == null) {singletonInstance = new Singleton();}return singletonInstance;}}}cs 4) initialization on demand holder idiom - 클래스 로딩 시점에 한번 호출됩니다.
- 내부 class를 생성시킴으로써 thread간 동기화 문제를 해결합니다.
- 일반적인 싱글톤 패턴의 사용 방법입니다.
1234567891011121314package Singleton;public class Singleton {// initialization on demand holder idiomprivate Singleton() {System.out.println("싱글톤 생성자 생성");}public static Singleton getInstance() {return DemandHolderIdiom.INSTANCE;}public static class DemandHolderIdiom {private static final Singleton INSTANCE = new Singleton();}}cs 5) enum initialization - Effective java 책에 소개되었던 방법입니다. enum type이 한번만 초기화되는점을 이용합니다.
1234567891011package Singleton;public enum Singleton {INSTANCE;private Singleton() {System.out.println("싱글톤 생성자 생성");}public static Singleton getInstance() {return INSTANCE;}}cs ※ 싱글톤 패턴 결과 확인
1234567891011121314151617181920package Singleton;public class TestSingtonMain {public static void main(String[] args) {// 싱글톤이 아닌 객체 클래스NotSingleton ns1 = new NotSingleton();NotSingleton ns2 = new NotSingleton();System.out.println("첫번째 객체 : " + ns1.hashCode());System.out.println("두번째 객체 : " + ns2.hashCode());System.out.println( ns1.equals(ns2) );System.out.println("*********************************************8");Singleton s1 = Singleton.getInstance();Singleton s2 = Singleton.getInstance();System.out.println("첫번째 객체 : " + s1.hashCode());System.out.println("두번째 객체 : " + s2.hashCode());System.out.println( s1.equals(s2) );}}cs ▶결과 화면
- 일반 클래스는 인스턴스를 만들때마다 생성자가 만들어지고 만들어진 객체가 다름을 볼 수 있지만,
싱글톤 패턴의 클래스로 만든 인스턴스는 생성자가 한번만 호출되고, 객체가 같음을 볼 수 있다.
반응형'DesignPattern' 카테고리의 다른 글
1. 템플릿 메소드 패턴 ( Template Method Pattern ) (0) 2018.07.18