제26조. 원시 유형을 사용하지 마십시오.
일반 다오 만들기
Generic을 사용하여 중복 코드를 제거하는 이점을 보여주기 위해 강의 중에 간단한 저장소를 만들었습니다.
public interface Entity {
Long getId();
}
public class Account implements Entity {
private Long id;
private String username;
public Account(Long id, String username) {
this.id = id;
this.username = username;
}
@Override
public Long getId() {
return this.id;
}
public String getUsername() {
return username;
}
}
public class Message implements Entity{
private Long id;
private String body;
@Override
public Long getId() {
return id;
}
public String getBody() {
return body;
}
}
각 개체는 Entity라는 인터페이스를 구현합니다.
public class AccountRepository {
private Set<Account> accounts;
public AccountRepository() {
this.accounts = new HashSet<>();
}
public Optional<Account> findById(Long id) {
return accounts.stream().filter(a -> a.getId().equals(id)).findAny();
}
public void add(Account account) {
this.accounts.add(account);
}
}
public class MessageRepository {
Set<Message> messages;
public MessageRepository() {
this.messages = new HashSet<>();
}
public Optional<Message> findById(Long id) {
return messages.stream().filter(a -> a.getId().equals(id)).findAny();
}
public void add(Message message) {
this.messages.add(message);
}
}
개체마다 고유한 리포지토리가 있는 경우 변경된 개체를 제외하고는 리포지토리 코드가 완전히 동일함을 알 수 있습니다.
이 중복 코드는 Generic으로 제거할 수 있습니다.
public class GenericRepository<E extends Entity> {
private Set<E> entities;
public GenericRepository() {
this.entities = new HashSet<>();
}
public Optional<E> findById(Long id) {
return entities.stream().filter(a -> a.getId().equals(id)).findAny();
}
public void add(E e) {
entities.add(e);
}
}
E의 타입을 Entity에서 상속받은 객체로 제한하고 그렇게 설계함으로써 중복 코드를 제거할 수 있습니다.
public class AccountRepository extends GenericRepository<Account>{
// private Set<Account> accounts;
//
// public AccountRepository() {
// this.accounts = new HashSet<>();
// }
//
// public Optional<Account> findById(Long id) {
// return accounts.stream().filter(a -> a.getId().equals(id)).findAny();
// }
//
// public void add(Account account) {
// this.accounts.add(account);
// }
}
그런 다음 AccountRepository에서 모든 코드를 제거하고 GenericRepository를 상속하기만 하면 됩니다!
@Test
void findById() {
AccountRepository accountRepository = new AccountRepository();
Account account = new Account(1L, "whiteShip");
accountRepository.add(account);
Optional<Account> byId = accountRepository.findById(1L);
Assertions.assertTrue(byId.isPresent());
}
제네릭을 사용하기 전과 제네릭 리포지토리를 상속한 후에 이 테스트를 실행하면 결과가 동일한 것을 확인할 수 있습니다.
정리하다
대학 졸업 후 항상 제네릭 서체를 만들어 사용하는 경우는 드문 것 같은데 이번 강의를 통해 사용법을 배웠습니다.
제 프로젝트에 이와 비슷한 코드가 많은데 바로 적용하고 싶어요!!
제네릭을 사용한다는 것은 앞으로 다른 엔티티가 추가된다고 해서 같은 코드를 다시 작성할 필요가 없고, GenericRepository<>만 확장하면 되기 때문에 훨씬 편리해 보입니다 ㅎㅎ

