Spring/Spring Boot

getter setter를 사용하는 이유

민돌v 2022. 2. 24. 16:48

 

 

👏🏻 놉! 왠만하면 사용하지 않는게 좋습니다.

게터는 편의성을 위해 어쩔수 없이 사용하는 부분이 있지만

Setter는 되도록 지양해야한다.  (2022.07 수정..ㅎ)

 

 

 


면접 스터디를 하면서 getter setter를 하는 이유에 대해 공부를 하는데 

새로 알게된 피드백을 받아서

이게 좀 헷갈려서 포스팅을 남기면서 공부를 해보고자 한다.

 

[공부 목적]

1. getter/ setter를 사용하는 이유는 데이터 무결성을 위해서 이다. (알고있던 것)

-> setter는 데이터 무결성을 해칠수도 있다(?)  (새롭게 알게된 것)

 

-> 따라서 builder 패턴이나 solid 개방패쇄 원칙에 대해 공부해보고자 한다.

 


1. 처음 공부한 것

 

Getter Setter를 사용하는 이유

핵심답변

  • 객체의 무결성을 보장하기 위해 사용합니다.
    • 예를 들어, 만약 외부에서 몸무게라는 필드에 직접 접근한다면 0보다 낮은 값을 줄 수도 있습니다. 이 경우 객체의 무결성이 깨지기 때문에 이를 방지하기 위해 Getter/Setter를 사용하여 데이터의 무결성을 지켜줍니다.

🤔 무결성이란 무엇인가요?

데이터의 정확성과 일관성을 유지하고 보증하는 것을 말합니다.

🤔 Getter/Setter를 사용할 때 왜 데이터 무결성이 지켜지나요?

Getter, Setter를 이용해서 데이터를 생성 및 접근을 하게 되면 들어오는 값을 바로 저장하는 게 아닌,
한번 검증하고 처리할 수 있도록 할 수 있기 때문에 데이터의 무결성이 지켜집니다.

  • Getter : 본 필드의 값을 숨긴 채 내부에서 가공된 값을 꺼낼 수 있다.
  • Setter : 필드를 private로 만들어 외부의 접근을 제한한 후, Setter를 사용해 전달받은 값을 내부에서 가공해 필드에 넣어줄 수 있다.

🤔 Getter/Setter를 사용할 때의 다른 이점은 없나요?

  1. Getter, Setter와 같은 엑세스 함수 사용 시, 위와 같은 데이터 무결성과 유효성 검사가 가능합니다.
  2. 객체의 필드를 private과 같은 접근제한자를 두면서 객체지향의 목적인 정보은닉이 가능합니다.

 


2. getter setter에 대한 피드백

피드백

  • Setter를 데이터 무결성과 연결하시면 면접관들이 읭?하실 가능성이 있습니다. 물론 추가 설명하시면 이해하시겠지만, Setter보다는 Builder 패턴이나 SOLID 개방폐쇄원칙에 더 적합한 주제입니다.

 

이 말에대해서 생각해보고, 같은 스터디 팀원분이 알려주셨느데,

무분별한 setter는 무결성을 해칠 수 있다.

단순히 setter로 데이터를 수정하면, 어떤 부분을 수정하는제, 어디서 데이터를 수정하는지 알 수 없다는 이야기다.

 

이러한 부분을 해결하기위해 Builder 패턴이라는 것을 사용하는데

Builder 패턴이란

복잡한 객체를 생성하는 방법을 정의하는 클래스와 표현하는 방법을 정의하는 클래스를 별도로 분리하여, 서로 다른 표현이라도 이를 생성할 수 있는 동일한 절차를 제공하는 패턴

이라고 한다.

 

아래와 같은 방식으로, Setter대신 각각의 필드를 생성하는 메소드를 작성해서 안전하게 사용하는 방법인 것 같다.

 

class Team {
    private String name;
    private int playCount;
    private int victoryPoint;
    private int winCount;
    private int drawCount;
    private int loseCount;
    private int scorePoint;

    public static Builder builder() {
        return new Builder();
    }

    public static class Builder {
        private String name;
        private int playCount;
        private int victoryPoint;
        private int winCount;
        private int drawCount;
        private int loseCount;
        private int scorePoint;

        private Builder() {
        }

        public Builder name(String name) {
            this.name = name;

            return this;
        }

        public Builder playCount(int playCount) {
            this.playCount = playCount;

            return this;
        }

        public Builder victoryPoint(int victoryPoint) {
            this.victoryPoint = victoryPoint;

            return this;
        }

        public Builder winCount(int winCount) {
            this.winCount = winCount;

            return this;
        }

        public Builder drawCount(int drawCount) {
            this.drawCount = drawCount;

            return this;
        }

        public Builder loseCount(int loseCount) {
            this.loseCount = loseCount;

            return this;
        }

        public Builder scorePoint(int scorePoint) {
            this.scorePoint = scorePoint;

            return this;
        }

        public Team build() {
            Team team = new Team();
            team.name = this.name;
            team.playCount = this.playCount;
            team.victoryPoint = this.victoryPoint;
            team.winCount = this.winCount;
            team.drawCount = this.drawCount;
            team.loseCount = this.loseCount;
            team.scorePoint = this.scorePoint;

            return team;
        }
    }
}
Team team = Team.builder()
                .name("맨유")
                .playCount(3)
                .victoryPoint(6)
                .winCount(2)
                .drawCount(0)
                .loseCount(1)
                .scorePoint(4)
                .build();



출처: https://multifrontgarden.tistory.com/207 [우리집앞마당]


 

Spring에서는 이 builder패턴을 지원하는 어노테이션이 존재한다.

public static class SignUpReq {

	private com.cheese.springjpa.Account.model.Email email;
	private Address address;

	@Builder
	public SignUpReq(Email email, String fistName, String lastName, String password, Address address) {
        this.email = email;
        this.address = address;
	}

	public Account toEntity() {
        return Account.builder()
            .email(this.email)
            .address(this.address)
            .build();
	}
}

public Account create(AccountDto.SignUpReq dto) {
    return accountRepository.save(dto.toEntity());
}
 

 

결론!

Getter와 Setter를 사용하는 이유는, 데이터를 보호하기 위함입니다. 

데이터를 불러올 때, 한번 더 가공하는 과정을 거침으로써, 내부 데이터가 결함을 가지지 않도록 하는 것 입니다.(무결성)

단, 무분별한 Setter는 데이터 무결성을 헤칠 수 있습니다.

 

이를 해결하기위해, 객체를 생성하는 생성자와, 이를 표현하는 메소드를 분리하여 사용하는 Builder 패턴을 이용해서 데이터 조금 더 직관적인 코드를 작성할 수 있습니다...!

 

 

spring 에서 lombok @builder 어노테이션으로 builder 패턴 사요하기 : https://velog.io/@aidenshin/%EB%82%B4%EA%B0%80-%EC%83%9D%EA%B0%81%ED%95%98%EB%8A%94-JPA-%EC%97%94%ED%8B%B0%ED%8B%B0-%EC%9E%91%EC%84%B1-%EC%9B%90%EC%B9%99