1주차 프리코스를 진행하며 아는 것과 모르는 것을 구분하는 법을 배울 수 있었다.
평소 알고 있다고 생각하고 사용했던 개념들에 대해 꼬리질문을 하니 대답할 수 없던 경우가 많았다.
과제를 진행함에 있어 내가 알고 있다고 생각했지만, 몰랐던 것들에 대해 정리를 해 보고자 한다.
1. 자바의 record 클래스
알고 있던 개념
1. record 는 단순히 값을 저장하는 용도의 클래스가 필요할 때 사용하는 클래스 타입이라는 점.
2. 내부 변수를 얻기 위해선(get), 변수명과 동일한 메서드로 접근하면 된다는 것(ex. record.value()).
더 조사하게 된 계기
1. 불변 객체를 만들기 위해 record 클래스를 만들고, 변수에 private final 을 붙였다. 하지만, 문법 오류가 발생했다.
2. 테스트를 위해 setter 를 만들었지만, 값을 set 하는 데에도 문법 오류가 발생했다. 내부 변수가 final 이라 set 이 불가능하다고 했다.
몰랐던 개념
1. record 는 변경 불가한(불변) 데이터를 저장하는 클래스를 쉽게 만들 수 있게 해 주는 클래스 타입이다.
→ 내부 변수가 자동으로 private final 로 설정된다.
2. 클래스 코드를 간결하게 하기 위해 사용되고, 값을 담는 데에 최적화되어있다.
3. 생성자(모든 변수를 매개변수로 받는), toString(), equals(), hashCode() 메서드가 자동으로 생성된다.
→ 이 점이 데이터를 저장하는 클래스를 “쉽게” 만들 수 있게 한다는 점에 크게 기여한다고 생각된다.
2. 자바의 final 키워드와 방어적 복사
알고 있던 개념
1. final 로 선언하면 해당 객체는 절대로 변경될 수 없다.
더 조사하게 된 계기
1. final 키워드를 통해 내부 List 변수를 선언했는데, getter 로 접근한 List 에 add() 로 값을 추가할 수 있던 상황을 접했다.
몰랐던 개념
1. final 은 변수의 "참조"를 변경할 수 없다는 의미였다.
Collection 처럼 내부 상태를 변경할 수 있는 자료구조에 final 을 붙이면, 재할당만 불가능하고, add() 등의 메서드는 사용 가능하다 → 값이 변경된다.
2. Collection을 불변 객체로 만들려면 불변 컬렉션을 사용하거나 방어적 복사를 수행해야 한다.
예를 들어, List.copyOf() 또는 Collections.unmodifiableList()를 사용하여 불변 리스트를 생성할 수 있다. 또는 새로운 컬렉션 객체를 생성하여 원본 데이터를 복사함으로써 외부 변경으로부터 보호할 수 있다.
방어적 복사를 수행하는 법
public class A {
List<Integer> values;
public A(List<Integer> values) {
this.values = List.copyOf(values); // A 내부에서도 값은 변경할 필요가 없는 경우.
}
public List<Integer> getValues(){
return List.copyOf(values); // 불변 List 로 방어적 복사.
}
}
3. 싱글톤 패턴을 사용하는 이유
알고 있던 개념
1. 싱글톤 패턴을 사용하면, 프로그램 전역에서 특정 클래스의 인스턴스가 한 개만 생성되게 할 수 있다.
2. 싱글톤의 구현하려면, 생성자를 private 으로 만든 뒤, 자신의 인스턴스를 자신이 관리하게 하면 된다.
더 조사하게 된 계기
1. 의존성 주입을 담당하는 클래스를 싱글톤으로 관리되면 되지 않을까? 하고 막연하게 생각했었다.
2. 하지만, 싱글톤으로 관리하는 데에 이점을 분석하는 과정에서 제대로 된 근거를 찾을 수 없었다.
의존성 주입 클래스는, 내부에서 의존성을 매핑해주고, getter 를 통해 의존성이 주입된 클래스의 인스턴스를 반환하고 있었다.
public class 의존성주입 { private final 클래스1 instance1= new 클래스1(); private final 의존성_클래스1 instance2 = new 의존성_클래스1(instance1); // .... public 의존성_클래스1 get의존성_클래스1() { return instance2; } }
의존성 주입 클래스는 Application 에서 Controller 를 생성하는 데에 쓰이고 있었고, Controller 를 제외한 어떠한 클래스에서도 사용되지 않고 있었다.
3. 의존성 주입 클래스를 막연하게 싱글톤으로 만들자고 생각하던 것을 보고, 싱글톤에 대한 이해가 부족하다고 느꼈다.
몰랐던 개념
1. 싱글톤을 왜 써야 하는가?
싱글톤 패턴의 장점
1. 유일 인스턴스를 가질 수 있다.
- 싱글톤 패턴이 적용된 클래스의 인스턴스는 애플리케이션 전역에서 단 하나만 존재하도록 보장된다.
- 여러 곳에서 하나의 인스턴스를 공유하므로, 불필요한 객체의 생성을 막을 수 있고, 여러 개의 객체가 생성되면서 발생할 수 있는 데이터 불일치를 방지할 수 있다.
2. 메모리를 절약할 수 있다.
- 애플리케이션 전역에서 하나의 인스턴스만 생성되므로, 여러 인스턴스 생성으로 인한 불필요한 메모리 자원 사용을 막을 수 있다.
2. 정말 싱글톤을 쓰는 게 더 좋은 선택이었는가?
의존성 주입을 하는 클래스가 싱글톤이면 어떤 것이 좋을까?
- 애플리케이션 전역에서 항상 같은 인스턴스(의존성이 주입된)를 얻을 수 있다.
- 하지만,
의존성 주입 클래스는 Application 에서 Controller 를 생성하는 데에 쓰이고 있었고, Controller 를 제외한 어떠한 클래스에서도 사용되지 않고 있었다 → 싱글톤으로써의 이점이 없었다.
4. JUnit5 의 @BeforeAll 과 생성자 방식의 차이
알고 있던 개념
1. 함수에 @BeforeAll 을 사용하면, 테스트 클래스가 초기화될 때, 처음 수행된다.
2. 보통, 테스트에 필요한 값을 설정할 때 사용한다.
더 조사하게 된 계기
1. 테스트 클래스에서 필요한 클래스들의 의존성을 주입하는 과정에서, @BeforeAll 을 사용했다. 하지만, @BeforeAll 이 테스트 클래스가 초기화될 때, 처음 수행된다면, 생성자와 다른 것은 무엇인지 의문이 들었다.
몰랐던 개념
1. @BeforeAll 과 생성자의 차이점
생성자는 테스트 클래스가 초기화될 때 수행된다.
@BeforeAll 도 마찬가지이다.
차이점은 뭘까?
- 생성자: 각 테스트 메서드가 실행될 때마다 새로운 인스턴스가 생성되므로, 생성자는 매 테스트마다 호출된다.
- @BeforeAll: 클래스의 모든 테스트 메서드가 실행되기 전에 한 번만 실행된다.
2. 테스트 클래스의 동작 원리
- 테스트 클래스는 각 테스트 메서드별로 독립적으로 테스트하기 위해, 각 테스트마다 새로 초기화된다.
확인을 위해 생성자와 @BeforeEach 를 각각 사용해 보았다.(더미 테스트 3개)
1. 생성자를 사용하는 경우
@DisplayName("BeforeAllTest 테스트")
public class BeforeAllTest {
public BeforeAllTest() {
System.out.println("초기화");
}
// 아래에는 항상 참인 테스트 메서드 세 개가 있음.
"초기화" 가 세 번 출력되었다.
2. @BeforeAll 을 사용할 경우
@DisplayName("BeforeAllTest 테스트")
public class BeforeAllTest {
@BeforeAll
static void beforeAll() {
System.out.println("초기화");
}
// 아래에는 항상 참인 테스트 메서드 세 개가 있음.
"초기화" 가 한 번 출력되었다.
'우아한테크코스 7기 프리코스' 카테고리의 다른 글
7기 프리코스 4주차 회고 (KPT 회고) (2) | 2024.11.12 |
---|---|
7기 프리코스 3주차 회고 (KPT 회고) (8) | 2024.11.05 |
7기 프리코스 2주차 회고 (2) | 2024.10.29 |