본문 바로가기

공부 자료/Spring

[Spring] @AllArgsConstructor, @NoArgsConstructor를 지양하자?

왜 생성자 애너테이션들을 지양해야 할까?

 

 

 

@AllArgsConstructor, @NoArgsConstructor  애너테이션을 지양해야 하는걸까?

 

이유를 알기 전 각각의 애너테이션이 무엇인지에 대해 먼저 알아보고자 한다.

 


 

@AllArgsConstructor, @NoArgsConstructor 애너테이션이란?

 

@NoArgsConstructor : 파라미터가 없는 디폴트 생성자를 생성

@AllArgsConstructor : 모든 필드 값을 파라미터로 받는 생성자를 생성

 

class Member{
	private String name;
    private Integer age;
    private String email;
    
    public Member(){} // 기본 생성자
    
    public Member(String name){
    	this.name = name;
    }
    
    public Member(String name, Integer age){
    	this.name = name;
        this.age = age;
    }
    
    public Member(String name, Integer age, String email){
    	this.name = name;
        this.age = age;
    	this.email = email;
    }
}

 

 

위의 코드는 기본 생성자와 그 외의 생성자들을 작성한 것인데, 이는 애너테이션을 사용할 경우 아래와 같이 간단하게 나타낼 수 있다.

 

@NoArgsConstructor
@AllArgsConstructor
class Member{
	private String name;
    private Integer age;
    private String email;
}

 

 


 

왜 이렇게 간단해지는 애너테이션 사용을 지양해야 할까?

 

 

@NoArgsConstructor를 지양해야 하는 이유

 

1. 불필요한 빈 객체 생성 가능성

매개변수가 없는 기본 생성자를 생성하는 애너테이션으로, 외부에서 불필요하게 객체를 생성 할 수 있게 되어,

객체의 의도와 목적에 맞지 않는 상태로 객체가 생성될 수 있음

 

2. 불변성 위반 가능성

불변의 객체를 설계할 때에는 초기화 이후 상태 변경이 불가능해야 하는데, 기본 생성자로 인해 생성 후에도 외부에서 필드를 수정할 수 있는 가능성이 존재할 수 있음

 

 

따라서 @NoArgsConstructor(access=accessLevel.PROTECTED)로 설정하여,

객체 내부에서 생성자를 하나로 만들어 활용하며 @Builder를 활용하는 것이 좋다.

 

최대한 지양해야 할 애너테이션은 @AllArgsConstructor이다.

 


 

@AllArgsConstructor를 지양해야 하는 이유

 

1. 불필요한 외부 의존성 증가

모든 필드를 인자로 받는 생성자를 생성하기 때문에 모든 필드에 대한 의존성이 증가하여 불필요한 의존성이 발생할 수 있는데,

이는 프로젝트가 커지고 여러 모듈이나 프로젝트 간 코드 공유에 문제를 야기할 수 있음

또한, 접근할 필요가 없는 필드값에 대해서도 접근할 수 있게 되어 접근 가능성을 최대화 할 수 있음

 

2. 캡슐화 원칙 위반

객체지향 프로그래밍에서는 캡슐화의 원칙을 지키며, 필요한 경우 getter/setter를 사용하는 것이 일반적인데 @AllArgsConstructor을 사용할 경우 모든 필드를 매개변수로 받는 생성자를 생성하여, 객체 내부 상태를 외부에서 직접 조작할 수 있는 가능성을 높임

 

3. 필드 순서에 따른 에러 발생

모든 필드를 인자로 받는 생성자를 생성하기 때문에 변수들의 순서에 영향을 받아 에러가 발생할 수 있음

@AllArgsConstructor
class Member{
	private String name;
    private String email;
}

Member member = new Member("hong@gmail.com", "홍길동");

 

* 이름이 이메일이 되고 이메일이 이름이 되는 현상이 발생할 수 있음

 

 


 

위와 같은 문제가 발생할 수 있기 때문에 @Builder를 사용하는 것이 좋다. 

@AllArgsConstructor 대신 Builder를 사용하면 어떻게 될지 예시를 하나 보고자 한다.

 

@AllArgsConstructor
class Member{
	private String name;
    private String email;
}

Member member = new Member("hong@gmail.com", "홍길동");

 

 

위에서 해당 코드의 문제를 보았는데 이 코드를 Builder를 사용하면 어떻게 될까?

 

@AllArgsConstructor
class Member{
	private String name;
    private String email;
    
    @Builder
    private Order(String name, String email){
    	this.name = name;
        this.email = email;
    }
}

Member member = Member.builder()
		.email("hong@gmail.com")
                    .name("홍길동")
                    .build();

 

위와 같이 파라미터를 순서가 아닌 이름으로 값을 지정하기 때문에 생성이나 리팩토링 시 유연하게 대응이 가능해진다.

 


 

오늘 얻은것은?

@AllArgsConstuctor은 최대한 지양하고, Builder를 이용하자!