이펙티브 자바-01.생성자 대신 정적 팩터리 메서드를 고려하라
아이템1. 생성자 대신 정적 팩터리 메서드를 고려하라
장점
- 이름을 가질 수 있다. 생성자에 비해 가독성이 좋다.
- 호출될 때마다 인스턴스를 새로 생성하지는 않아도 된다.
- 반환 타입의 하위 자료형 객체를 반환할 수 있는 능력이 있다..
- 입력 매개변수에 따라 매번 다른 클래스의 객체를 반환할 수 있다.
- 정적 팩토리 메서드를 작성하는 시점에는 반환할 객체의 클래스가 존재하지 않아도 된다.
단점
- 정적 팩토리 메서드만 있는 클래스라면, 생성자가 없으므로 하위 클래스를 못 만든다.
- 정적 팩토리 메서드는 다른 정적 메서드와 잘 구분되지 않는다. (문서만으로 확인하기 어려울 수 있음, 프로그래머가 찾기 어렵다.)
코드를 통한 이해
장점1. 가독성이 좋다
다음은 캐릭터 클래스이다.(직업이 전사, 마법사 존재)
class Character {
int intelligence, strength, hitPoint, magicPoint;
public Character(int intelligence, int strength, int hitPoint, int magicPoint) {
this.intelligence = intelligence; // 지능
this.strength = strength; // 힘
this.hitPoint = hitPoint; // HP
this.magicPoint = magicPoint; // MP
}
// 정적 팩토리 메소드
public static Character newWarrior() {
return new Character(5, 15, 20, 3); // 전사는 힘과 HP가 높다
}
// 정적 팩토리 메소드
public static Character newMage() {
return new Character(15, 5, 10, 15); // 마법사는 지능과 MP가 높다
}
}
만약 생성자를 사용해 전사나 마법사를 생성한다면 다음과 같을 것이다.
Character warrior = new Character(5, 15, 20, 3);
Character mage = new Character(15, 5, 10, 15);
변수명이 없었다면 5, 15, 20, 3 같은 연속된 숫자만으로는 캐릭터의 직업을 알아보기 어려웠을 것이다.
하지만 정적 팩토리 메서드를 사용한다면 좀 더 읽기 쉬운 코드가 된다.
Character warrior = Character.newWarrior();
Character mage = Character.newMage();
장점2. 호출될 때마다 인스턴스를 새로 생성하지는 않아도 된다.
Boolean.valueOf(boolean) 같은 경우 객체를 아예 생성하지 않는다.
반환만 한다, 비싼 new 를 계속 사용하지 않는다.
이해하기 좀 더 쉽게 코드로 살펴보면..
일반적으로 테스트 코드를 작성하면서 보았겠지만
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.model;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.view;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.request;
@ExtendWith(SpringExtension.class)
@WebMvcTest
class SampleControllerTest {
@Autowired
MockMvc mockMvc;
@Test
public void eventForm() throws Exception {
mockMvc.perform(get("/events/form"))
.andDo(print())
.andExpect(view().name("events/form"))
.andExpect(model().attributeExists("event"))
.andExpect(request().sessionAttribute("event", notNullValue()))
;
}
public abstract class MockMvcResultMatchers {
private static final AntPathMatcher pathMatcher = new AntPathMatcher();
public static RequestResultMatchers request() {
return new RequestResultMatchers();
}
public static HandlerResultMatchers handler() {
return new HandlerResultMatchers();
}
public static ModelResultMatchers model() {
return new ModelResultMatchers();
}
...
정적 메서드를 사용한 것을 볼 수 있다.
한번만 new로 생성해놓고, 계속 사용한다.