JAVA/JAVA | Spring 학습기록

[Java] 자바 final의 역할과 싱글톤 패턴

kth990303 2021. 9. 22. 16:39
반응형

스프링 MVC 2편을 듣던 도중, 싱글톤 패턴 관련 내용이 나와서

오랜만에 싱글톤 패턴 내용을 복습하던 중 final에 대한 궁금증이 생겨서 공부한 내용을 포스팅해보려 한다.

(역시 Java 기본기가 중요한듯하다.)

 

먼저 singleton pattern이 어떤 과정에서 필요하게 됐는지부터 서술하겠다.


싱글톤 패턴이 필요했던 이유

 

Controller에서 model에 attribute할 때, 똑같은 객체를 여러 메소드에서 attribute해야 하는 경우가 생길 수 있다.

이럴 경우 코드가 중복되며, 코드 길이가 길어지기 때문에 가독성 또한 좋지 않다.

 

List와 같은 컬렉션 객체를 컨트롤러 내의 수많은 메소드에 attribute하기엔 중복되는 코드가 많기 때문에 @ModelAttribute 관련 메소드를 아래와 같이 따로 만들어주었다.

    @ModelAttribute("deliveryCodes")
    public List<DeliveryCode> deliveryCodes(){
        List<DeliveryCode> deliveryCodes = new ArrayList<>();
        deliveryCodes.add(new DeliveryCode("FAST", "빠른 배송"));
        deliveryCodes.add(new DeliveryCode("NORMAL", "일반 배송"));
        deliveryCodes.add(new DeliveryCode("SLOW", "느린 배송"));
        return deliveryCodes;
    }

그러나 위와 같이 진행할 경우, 아래와 같은 문제점이 존재한다.

출처: 김영한님의 스프링 MVC 2편 강의교재 일부

따라서 어떤 수강생분께서 좋은 질문을 해주셨다.

https://www.inflearn.com/questions/257492

 

미리 사용할 정보를 다음과 같이 구현하면 되는 것인지 궁금합니다!!! - 인프런 | 질문 & 답변

안녕하세요 강사님. 항상 좋은 수업 감사드립니다. 다름이 아니라 @ModelAttribute를 사용하면 매번 생성하는 문제가 있다고 하셔서 한번 제 생각대로 구현해봤습니다. 이전 Memory에 사용했던 싱글톤

www.inflearn.com

싱글톤 패턴을 사용하면 수많은 메소드를 호출할 때마다 List<DeliveryCodes> 객체가 새로 생성되지 않고 공유할 수 있다.

 

예전에 싱글톤 패턴은 단점이 너무 커서 자주 사용하지 않는다고 하여 한귀로 듣고 한귀로 흘린 기억이 있는데, 유용하게 사용될 때도 존재함을 깨닫게 된 순간이다.

 

자세한 내용은 아래 블로그의 포스팅에서 볼 수 있다.

https://injae-kim.github.io/dev/2020/08/06/singleton-pattern-usage.html

 

Injae's devlog

현실의 문제를 해결하는 엔지니어

injae-kim.github.io


근데 final은 왜?

근데 왜 내가 final을 궁금해하는 것인지 궁금해할 수 있다.

그 이유는 아래와 같다.

 

위 질문글에서는 싱글톤 패턴을 다음과 같이 적용했다.

public class DeliveryCodesInstanceMake {
    private static final List<DeliveryCode> deliveryCodes = Arrays.asList(
            new DeliveryCode("FAST", "빠른 배송"),
            new DeliveryCode("NORMAL", "일반 배송"),
            new DeliveryCode("SLOW", "느린 배송")
    );

    public static List<DeliveryCode> getInstance() {
        return deliveryCodes;
    }

    private DeliveryCodesInstanceMake() {
    }
}

그리고 다른 블로그에서는 싱글톤패턴을 아래와 같이 적용했다.

public class DeliveryCodesInstanceMake {
    private static List<DeliveryCode> deliveryCodes; 

    public static List<DeliveryCode> getInstance() {
    	if(deliveryCodes == null){
        	// deliveryCodes 생성
        }
        return deliveryCodes;
    }

    private DeliveryCodesInstanceMake() {
    }
}

둘의 차이점이 느껴지는가?

인스턴스를 바로 생성했느냐, 생성하지 않았느냐의 차이다.

또한, 인스턴스 변수에 final이 붙었느냐, 붙지 않았느냐의 차이이기도 하다.

참고로 위 코드의 deliveryCodes 변수에 final을 붙이면 컴파일 에러가 발생한다.

 

사실 나는 final을 잘 몰랐기 때문에 아래와 같이 코드를 작성해버리면 null일경우도 리턴해버리는 것이 아닐까 걱정했다.

  public static List<DeliveryCode> getInstance() {
        return deliveryCodes;
    }

그러나 전혀 걱정할 필요가 없었다.

 

final 필드를 선언할 경우, 초기화하지 않을 경우 컴파일 에러를 발생시키기 때문이다.

즉, private static final List<DeliveryCode> deliveryCodes; 를 선언해놓고 초기화를 하지 않으면 컴파일 에러가 발생한다는 것이다.

 

또한, final 필드가 한번 초기화되면 이후 수정이 불가능하다.

이는 final 필드가 상수를 의미하기 때문이다.

 

정리하자면, final 필드는 선언할 때 그 즉시 초기화를 해주어야 하며, 한번 초기화한 이후로는 재생성(수정)이 불가능하다!

 

즉, 싱글톤 패턴과 같이 한번 선언할 때 생성되고, 그 이후에 생성을 막아줄 때 final필드를 사용하면 아주 적절하다는 것.

그래서 위 두 코드 모두 싱글톤 패턴 코드로 적절하다는 것이다~

 

개인적으로 난 가독성이 조금 더 괜찮다고 생각되는 아래 코드를 사용할 것 같다.

public class DeliveryCodesInstanceMake {
    private static List<DeliveryCode> deliveryCodes;

    public static List<DeliveryCode> getInstance() {
        if(deliveryCodes==null){
            deliveryCodes=Arrays.asList(
                    new DeliveryCode("FAST", "빠른 배송"),
                    new DeliveryCode("NORMAL", "일반 배송"),
                    new DeliveryCode("SLOW", "느린 배송")
            );
        }
        return deliveryCodes;
    }

    private DeliveryCodesInstanceMake() {
    }
}

어서 군복학하고 Java프로그래밍 수업을 듣든지 해야겠다.

반응형