저번시간에 AppConfig로 다른 클래스에 객체를 주입하는 방식으로 리팩토링하면서 클래스들이 구현 객체에 의존하는 게 아니라 추상 객체인 인터페이스에 의존하게 변경하여 DIP와 OCP 원칙을 지켜봤다. 이러면 이제 모든 클래스에서 AppConfig 객체를 생성하고 클래스 생성자를 만들어주면 생성자를 통해 객체를 주입받아 사용할 수 있게 되었을 것이다.
그런데 이렇게 될 경우 사용자가 요청을 할때마다 객체가 AppConig 객체가 생성되고 그 안에 있는 객체 또한 전부 생성되어 메모리 낭비가 과해진다. 사용자가 적다면 문제 없겠지만 1000명, 10000명이 넘어가는 순간 서버가 다운되고 말것이다.
@Test
@DisplayName("스프링 없는 순수한 DI 컨테이너")
void pureContainer() {
AppConfig appConfig = new AppConfig();
MemberService memberService1 = appConfig.memberService();
MemberService memberService2 = appConfig.memberService();
System.out.println("memeberService1 = " + memberService1);
System.out.println("memeberService2 = " + memberService2);
assertThat(memberService1).isNotSameAs(memberService2);
}
이런 문제를 해결하기 위해 싱글톤 패턴이라는 것을 사용할 수 있는데 싱글톤 패턴은 클래스에서 static 영역으로 객체를 미리 딱 하나만 생성해두고 static 메서드를 통해서만 조회하도록 허용해 사용하고자 하는 클래스에서 해당 메서드를 통해 미리 생성된 객체를 가져와 공유하는 방식으로 설계하는 것이다.
public class SingletonService {
//1. static 영역에 객체를 딱 1개만 생성해둔다.
private static final SingletonService instance = new SingletonService();
//2. public으로 열어서 객체 인스턴스가 필요하면 이 static 메서드를 통해서만 조회하도록 허용한
다.
public static SingletonService getInstance() {
return instance;
}
//3. 생성자를 private으로 선언해서 외부에서 new 키워드를 사용한 객체 생성을 못하게 막는다.
private SingletonService() {
}
public void logic() {
System.out.println("싱글톤 객체 로직 호출");
}
}
이제 다른 클래스에선 getInstance 메서드를 통해 미리 생성된 객체를 가져와 공유한다. 이렇게 하면 고객의 요청이 올때마다 같은 객체만 사용하여 매모리를 효율적으로 사용할 수 있다.
그런데 이 싱글톤 패턴에는 많은 문제가 있다.
- 싱글톤 패턴을 구현자체에 많은 코드가 필요하다.
- 의존관계상 클라이언트가 구체 클래스에 의존하게 된다.
- 구체 클래스에 의존하기 때문에 나중에 확장할 때 OCP 원칙을 위반할 가능성이 높아진다.
한마디로 말하면 유연성이 매우 떨어진다는 것이다.
스프링의 컨테이너는 위와 같은 걸 적용하지 않아도 빈으로 등록하는 것만으로도 이 모든 단점을 해결하면서 객체를 싱글톤으로 관리하도록 도와준다.
싱글톤 방식의 주의점
싱글톤 패턴은 위에서 말한대로 하나의 객체를 다양한 사용자가 공유할 수 있도록 만드는 것이라 주의해야 하는 부분이 있다.
- 특정 클라이언트가 값을 변경할 수 있는 필드가 있으면 안된다.
- 특정 클라이언트에 의존적인 필드가 있으면 안된다.
- 가급적 읽기만 가능해야 한다.
이것은 한 사용자가 로그인했는데 다른 사용자의 계정내역이 보이거나, 누군가 결제를 했는데 다른 사용자의 결제금액이 적용되거나 하는 큰 문제로 이어질 수 있기 때문에 항상 유의하도록 하자!
'개발 > 내일배움캠프 TIL' 카테고리의 다른 글
[TIL #26] 키오스크 과제 완성 그리고 그 과정 (0) | 2024.11.27 |
---|---|
[TIL #25] 키오스크 과제 리팩토링에 대한 고민 (0) | 2024.11.27 |
[TIL #22] 키오스크 DIP, OCP 원칙 지키기 (0) | 2024.11.22 |
[TIL #21] 키오스크 과제 설계 및 중간 리팩토링 (0) | 2024.11.21 |
[TIL #20] 의존관계 주입 DI 와 제어의 역전 IoC (0) | 2024.11.21 |