⭐디자인 패턴⭐

p_chan.log·2022년 8월 20일
0

JAVA

목록 보기
12/17

🔴디자인 패턴

💠1. Single Ton 디자인 패턴

1-1. 디자인 패턴 이란?

  • 소프트웨어를 설계할 때 특정 맥락에서 자주 발생하는 고질적인 문제들이
    발생했을 때 재사용할수 있는 해결책

1-2. SingleTon 디자인 패턴

  • 프로그램 내의 여러 곳에서 반복적으로 사용되어야 하는 객체에 대해 전역적인
    범위를 갖도록 객체를 생성하고, 이 객체를 여러 곳에서 공유하기 위한 클래스
    작성 패턴
  • 이러한 패턴을 통해 생성된 객체를 싱글톤 객체라고한다.

1-3. SingleTon 객체의 이점

  • 프로그램의 전역에서 활용할 재료로 사용되는 공유 기능을 하나만 생성하여
    여러곳에서 재사용함으로 해서 메모리를 효율적으로 사용할 수 있다.
  • 단 한번만 객체를 생성하면 다시 객체를 생성할 필요가 없기 때문에,
    해당 기능을 사용할 때마다 객체를 일일이 생성해야 하는 번거로움을 피할 수 있다.

✍️싱글톤 패턴의 구현 방법

1. 싱글톤 패턴의 가장 기본적인 구현

public class Singleton {
    
    // 단 1개만 존재해야 하는 객체의 인스턴스, static 으로 선언
    private static Singleton instance;

    // private 생성자로 외부에서 객체 생성을 막음
    private Singleton() {}

    // 외부에서는 getInstance() 로 instance 를 반환
    public static Singleton getInstance() {
      // instance 가 null 일 때만 생성
      if (instance == null){
          instance = new Singleton();
      }
      return instance; 
    } 
}
  • 싱글톤 패턴의 기본적인 구현 방법 입니다.
  • private 생성자 로 외부에서 객체 생성을 막으며, getInstance() 함수 로만 instance 에 접근이 가능하게 만듭니다.
  • instance 는 static 변수 로 선언되며 getInstance() 가 최초로 호출 될 때 에는 null 이므로 한 번만 생성하고, 이후에는 생성해놨던 instance 를 반환합니다.
  • 따라서 다른 함수에서 getInstance() 를 여러 번 호출 하더라도 단 하나의 동일한 instance 만을 반환 해 줍니다.
  • 마치 앞에서 살펴봤던 예시 처럼 여러명이 하나의 프린터를 사용하는 상황과 동일한 구현인 것 이죠!
  • 하지만, 위의 코드는 멀티 스레드 환경에서 Thread-Safe 를 보장해주지 않습니다.
  • 두 개의 스레드에서 동시에 getInstance() 를 호출 한경우 에
    if (instance == null) 조건문에 동시에 도달하게 되어 instance 를 두번 생성할 수 도 있기 떄문이죠!
  • 이를 해결하기 위해, Java 에서 스레드 동기화를 지원하는 Synchronzied 를 사용할 수 있습니다.

2. Synchronized 를 사용하여 Thread-Safe 를 보장하는 싱글톤 패턴

public class Singleton {

private static Singleton instance;

private Singleton() {}

// synchronzied 스레드 동기화를 사용하며 멀티 스레드 환경에서의 동시성 문제 해결
public static synchronzied Singleton getInstance() {
  if(instance  == null) {
     instance  = new Singleton();
  }
  return instance;
  }
}
  • 위처럼, 여러개의 스레드가 동시에 호출 할 수 있는 getInstance() 함수에 Synchronzied 를 적용하여 멀티 스레드 환경에서 getInstance() 함수 호출 시에 발생할 수 있는 동시성 문제를 해결 할 수 있습니다.
  • Synchronzied 의 가장 큰 단점은, Thread-Safe 를 보장하기 위해 속도를 포기했다는 점 입니다.
  • Synchronzied 를 적용하면 보통 적용하지 않았을 때 보다 약 100배 정도 속도가 느려지는 단점이 있다고 알려져 있습니다. 물론 정확한 수치는 직접 측정해 봐야 알겠지만, 어쩄든 성능저하가 있는 것은 확실하죠.

3. Double Check를 사용하여 Thread-Safe 를 보장하는 싱글톤 패턴

public class Singleton {
    private volatile static Singleton instance;

    private Sigleton() {}
    
    // Double check
    public Singleton getInstance() {
     // instance 가 null 인 경우
     if(instance == null) {
         // synchronized 를 적용한 후, 한번 더 instance 가 null 인지를 체크
         synchronized(Singleton.class) {
            if(instance == null) {
               instance = new Singleton(); 
            }
         }
      }
      return uniqueInstance;
    }
}
  • Double Check 의 아이디어는, getInstace() 함수 전체에 Synchronzied 를 적용하는 것을 개선하기 위해 Synchronzied 를 사용하지 않고 instance 가 null 인지를 확인한 후, null 이라면 이때서야 Synchronzied 를 적용하여 스레드 동기화를 한 후 instance 가 null 인지 다시한번 체크하는 방법 입니다.
  • 처음부터 Synchronzied 를 적용하기 보다 느리게, 게으르게 Synchronzied 를 적용하여 한번 더 체크하는 것 이죠!
  • 이러한 아이디어는 Lazy~ 라는 키워드로 컴퓨터 공학의 다양한 분야에 적용되는 성능 개선 방식입니다.
  • 굳이 처음부터 정직하게 스레드를 동기화 하여 확인할 필요는 없는 것 이죠! instance 가 null 이라면 그때 가서Synchronzied 를 적용한 후에 게으르게 한번 더 확인하면 되니까요.
  • 이처럼 Lazy 한 Double Check 방식으로 Synchronzied 의 속도 저하를 어느정도 개선할 수 있습니다.

4. LazyHolder 를 사용하는 싱글톤 패턴

public class Singleton {

    private Singleton() {}
    
    // private static inner class 인 LazyHolder
    private static class LazyHolder {
    // LazyHolder 클래스 초기화 과정에서 JVM 이 Thread-Safe 하게 instance 를 생성
        private static final Singleton instance = new Singleton();
    }

    // LazyHolder 의 instance 에 접근하여 반환
    public static Singleton getInstance() {
        return LazyHolder.instance;
    }
    
}
  • Java 진영에서 가장 많이 사용되는 LazyHolder 를 사용하는 싱글톤 패턴 입니다.
  • private static class 인 LazyHolder 안에 instace 를 final 로 선언하는 방법인데요,
  • JVM (Java Virtual Machine) 의 클래스의 초기화 과정에서 원자성을 보장하는 원리를 이용하는 방식입니다.
  • getInstance() 가 호출되면 LazyHolder의 instance 변수에 접근하는데요, 이때 LazyHolder 가 static class 이기 때문에 클래스의 초기화 과정이 이루어 집니다.
  • LazyHolder 클래스가 초기화 되면서 instance 객체의 생성도 이루어 지는데요, JVM 은 이러한 클래스 초기화 과정에서 원자성을 보장합니다.
  • 따라서, final 로 선언한 instance 는 getInstace() 호출 시 LazyHolder 클래스의 초기화가 이루어 지면서 원자성이 보장된 상태로 단 한번 생성되고, final 변수 이므로 이후로 다시 instance 가 할당되는 것 또한 막을 수 있습니다.
  • 이러한 방법에 장점은 Synchronzied 를 사용하지 않아도 JVM 자체가 보장하는 원자성을 사용하여 Thread-Safe 하게 싱글톤 패턴을 구현할 수 있는 것 입니다.

2. MVC패턴

2-1. MVC패턴

- M : Model
	-> 사용자가 원하는 데이터나 정보를 제공
	-> 애플리케이션의 정보, 데이터를 나타낸다.
	-> 이러한 data, 정보들의 가공을 책임지는 영역을 말한다.
- V : View
	-> 보여지는 화면
	-> input 텍스트, 체크박스 항목 등과 같은 사용자의 인터페이스 요소를
	나타냅니다. 데이터 및 객체의 입력, 그리고 보여주는 출력을 담당한다.
	-> 데이터를 기반으로 사용자들이 볼 수 있는 화면이다.
- C : Controller
	-> 사용자의 요청을 처리하고,  그 요청에 따른 전체적인 흐름 제어
	-> 데이터와 사용자 인터페이스 요소들을 잇는 다리역할을 한다.

2-2. MVC model1(MVC1)

- MVC1 패턴의 경우 View와 Controller를 모두 JSP가 담당하는 형태를 가진다.
즉, JSP하나로 유저의 요청을 받고 응답을 처리하므로 구현의 난이도는 쉽다.
- 단순한 프로젝트에는 괜찮겠지만, 내용이 복잡하고 거대해질수록 이 패턴은
힘을 잃는다. 즉 유지보수에 있어서 문제가 발생한다.

2-3. MVC model2(MVC2)

  - MVC2패턴은 널리 표준으로 사용되는 패턴입니다.
  - 요청을 하나의 컨트롤러(Servlet)가 먼저 받는다. 즉 MVC1과는 다르게
	Controller, View가 분리되어 있다.
  - 따라서 역할이 분리되어 MVC1 패턴에서의 단점을 보완할 수 있다.
  - 그러므로 개발자는 M,V,C 중에서 수정해야 할 부분이 있다면, 그것만
 	 꺼내어 수정하면 된다.
profile
개발자 박찬의 노트

0개의 댓글