반응형
아이템 26 - 로 타입은 사용하지 말라 - 완벽 공략
이 글은 백기선 님의 이펙티브 자바 강의와 이펙티브 자바 3 / E 편을 참고하여 작성하였습니다.
Generic DAO 만들기
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
인터페이스가 있고 Account
와 Message
는 이 인터페이스를 구현하고 있다.
이 두 클래스는 각각의 Repository
를 가지고 있다.
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 {
private 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);
}
}
각각의 Repository
의 메서드들은 거의 동일하다.
이러한 경우가 굉장히 많다.
리플렉션과 제네릭을 활용하면 상당히 많은 양의 코드를 줄일 수 있고, 그만큼 유지보수에 용이해진다.
class AccountRepositoryTest {
@Test
void findById() {
AccountRepository accountRepository = new AccountRepository();
Account account = new Account(1L, "whiteship");
accountRepository.add(account);
Optional<Account> byId = accountRepository.findById(1L);
assertTrue(byId.isPresent());
}
}
제네릭 코드를 사용하기 전에 테스트 코드를 먼저 작성하자.
public class GenericRepository {
}
GenericRepository
를 생성한다.
public class GenericRepository {
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);
}
}
그 뒤 GenericRepository
에 AccountRepository
코드를 그대로 복사한다.
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 account) {
this.entities.add(account);
}
}
제네릭 타입을 <E extends Entity>
로 선언해 Entity
클래스를 상속받은 타입으로 한정짓는다.
그 뒤 제네릭을 사용하는 코드로 수정한다.
public Optional<E> findById(Long id) {
return entities.stream().filter(a -> a.getId().equals(id)).findAny();
}
위의 메서드에서 getId()
를 사용할 수 있었던 이유는 <E extends Entity>
를 사용해
Entity
클래스의 하위 타입을 받았기 때문이다.
public class AccountRepository extends GenericRepository<Account> {
}
위처럼 GenericRepository
를 상속받아 사용할 수 있다.
새로운 Entity
가 추가도 쉽게 할 수 있다.
반응형
'개발 공부 > Java' 카테고리의 다른 글
이펙티브 자바 아이템 27 - 비검사 경고를 제거하라 - 완벽 공략 (0) | 2022.12.09 |
---|---|
이펙티브 자바 아이템 27 - 비검사 경고를 제거하라 - 핵심 정리 (0) | 2022.12.08 |
이펙티브 자바 아이템 26 - 로 타입은 사용하지 말라 - 핵심 정리 (1) | 2022.12.07 |
이펙티브 자바 아이템 25 - 톱 레벨 클래스는 한 파일에 하나만 담으라 - 핵심 정리 (0) | 2022.12.02 |
이펙티브 자바 아이템 24 - 멤버 클래스는 되도록 static 으로 만들라 - 완벽 공략 (0) | 2022.12.02 |
댓글