ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 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를 할 수 없다. 

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    package 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 - 클래스 로딩 시점에 미리 객체를 생성하고, 변수 셋팅 및 에러 처리를 위한 구문을 넣습니다.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    package Singleton;
     
    public class Singleton {
        //static block initialization
        private 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 메소드를 동기화하면 프로그램 느려집니다.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    package 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간 동기화 문제를 해결합니다.

                                                                      - 일반적인 싱글톤 패턴의 사용 방법입니다.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    package Singleton;
     
    public class Singleton {
        // initialization on demand holder idiom
        private 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이 한번만 초기화되는점을 이용합니다.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    package Singleton;
     
    public enum Singleton {
        INSTANCE;
        private Singleton() {
            System.out.println("싱글톤 생성자 생성");
        }
        public static Singleton getInstance() {
            return INSTANCE;
        }
    }
    cs



      ※ 싱글톤 패턴 결과 확인

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    package 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
Designed by Tistory.