아래는 내가 프로젝트를 하면서 작성했던 Entity 클래스다.
JPA 를 사용할 때, Entity 에서 @Getter 와 함께 @Setter 를 사용했다.
@Entity
@Getter
@Setter
@Table(name = "board")
@NoArgsConstructor
public class Board extends Timestamped {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "title", nullable = false)
private String title;
@Column(name = "username", nullable = false)
private String username;
@Column(name = "password", nullable = false)
private String password;
@Column(name = "contents", nullable = false, length = 500)
private String contents;
// 게시글 작성
public Board(BoardRequestDto requestDto) {
this.title = requestDto.getTitle();
this.username = requestDto.getUsername();
this.password = requestDto.getPassword();
this.contents = requestDto.getContents();
}
// 게시글 수정
public void update(BoardRequestDto requestDto) {
this.title = requestDto.getTitle();
this.username = requestDto.getUsername();
this.password = requestDto.getPassword();
this.contents = requestDto.getContents();
}
}
금지까지는 아니지만, 지양하는 것이 좋다고 한다.
(필요할 경우 사용해도 된다.)
Post post = new Post();
post.setId(1L);
post.setUserId("member1");
post.setTitle("제목입니다.");
post.setCont("내용입니다.");
post 엔티티 클래스를 set메서드를 통해 변화를 주고 있다.
그러나 set 메서드가 게시글의 값을 생성하는 것인지? 기존 값을 수정/변경하는 것인지?
그 의도 파악이 어렵다.
// 게시글 수정
public Post updatePost(Long id) {
Post post = findById(id);
post.setTitle("제목을 수정합니다.");
post.setCont("내용을 수정합니다,");
return post;
}
게시글 수정 메서드의 접근 제한자는 'public'이다.
따라서, 어디든(모든 메서드가) 접근이 가능하다.
(참고: 캡슐화, 접근 제한자, Getter/Setter, 문제점 및 대안)
그러나
본래 의도와는 달리, post 값을 변경해버리는 경우가 생길 수도 있다.
즉, 일관성 유지를 할 수 없게 돼버린다.
Entity
@Getter
@Entity
public class Post {
private Long id;
private String userId;
private String title;
private String cont;
// 게시글 수정
public void updatePost(Long id, String title, String cont) {
this.id = id;
this.title = title;
this.cont = cont;
}
}
service
// 게시글 수정
public void ... (...) {
...
post.updatePost(1L, "수정할 제목입니다.", "수정할 내용입니다.");
}
@Builder
를 사용한다.
생성 시점에 값을 넣음으로써, 일관성을 유지할 수 있다.
요구사항에 맞게 필요한 데이터만 사용해서, 유연한 클래스 생성이 가능하다.
전체에서 생성자 하나만을 가지게 되므로, 유지보수↑ 가독성↑
객체를 생성 시, 인자 값의 순서가 상관X
Entity
@Getter
@Builder // builder 설정
@NoArgsConstructor
@AllArgsConstructor
@Entity
public class Article {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String image;
private String title;
private String date;
private String content;
private String tag;
}
service
private List<ArticleListResponseDto> processUrl(String url) throws IOException {
Document document = Jsoup.connect(url).get();
Elements contentList = document.select("div div.section-list-area div.list");
List<ArticleListResponseDto> articleResponseDtoList = new ArrayList<>();
for (Element contents : contentList) {
String image = contents.select("a img").attr("abs:src");
String title = contents.select("h4 a").text();
String date = contents.select("p span").text().substring(0, 10).replaceAll("-", "/");
String tag = contents.select("strong a").text();
String articleLink = contents.select("h4 a").attr("abs:href");
Document articleDocument = Jsoup.connect(articleLink).get();
String content = articleDocument.select("div div.text").text();
Article article = Article.builder() // builder 사용
.image(image)
.title(title)
.tag(tag)
.date(date)
.content(content)
.build();
articleRepository.save(article);
articleResponseDtoList.add(new ArticleListResponseDto(article));
}
return articleResponseDtoList;
}
builder 를 통해, 값의 세팅도 가능하다.
만약, setter 를 그대로 사용했다면?
Article article = new Article();
article.setId(currentId);
article.setImage(image);
article.setTitle(title);
article.setDate(date);
article.setTagName(tagName);
article.setContent(content);
public class Member {
private String name;
private String age;
public Member(String name){
this.name = name;
}
public Member(String name,int age){
this.name = name;
this.age = age;
}
문제점
멤버 변수多 + 생성자多 경우, 코드多 가독성↓
이를 해결하기 위해 Builder 패턴을 사용한다.
public class Member {
private String name;
private String age;
public static void createMember(String name, int age){
this.name = name;
this.age = age;
}
public static void createMemberName(String name){
this.name = name;
}
이름(createMember, createMemberName ...)을 가질 수 있으므로, 반환될 데이터를 추측할 수 있다.
핵심은 setter 의 외부 노출을 줄이는 것이기 때문에
하나의 필드만 변경할 경우 등... 일부 상황에서는 Setter 를 사용해도 큰 문제가 없다.