NextStep을 학습하다...
'경계'와 '일급 콜렉션'이란 것을 알게 되었다.
한 포스팅에 담기엔 내용이 좀 길어져서
따로 포스팅을 하는 것이다.
(일급 컬렉션에 대해서는 맨 아래 출처 링크가서 보시는 게 더 나을 겁니다.
특히 이동욱 개발자님 블로그 추천합니다.
저는 지식 전달보다는 학습에 초점을 맞출 것이라 많이 축약해서 올릴 예정입니다.)
먼저 '경계'를 알아보자.
✔️ 경계
1. 외부 코드 사용하기
- API를 사용하는 사용자는 자신의 요구에 집중하는 인터페이스만 존재하기를 기대한다.
- java.util.List, java.util.Map과 같은 collection을 외부에 노출하는 경우, 사용자는 너무 많은 인터페이스에 노출하게 된다.
Map<Integer, Sensor> sensors = new HashMap<>();
...
Sensor s = sensors.get(sensorId);
→ Map<Integer, Sensor> 인스턴스를 여기저기로 넘긴다면, Map 인터페이스가 변할 경우, 수정할 코드가 상당히 많아진다.
다음은 Map을 좀 더 깔끔하게 사용한 코드다.
- 경계 인터페이스인 Map을 Sensor라는 클래스 안으로 숨긴다.
public class Sensor {
Map<Integer, Sensor> sensors = new HashMap<>();
public Sensor getById(String id) {
return sensors.get(id);
}
// 이하 생략
}
- Sensors 사용자는 제네릭스가 사용되었는지 여부에 신경 쓸 피룡가 없다.
- 위와 같이 Map을 사용자에게 직접 노출하는 경우, 사용자에게 Map의 모든 인터페이스를 노출하지 않아도 된다.
- Sensors를 추가함으로써 필요한 인터페이스 하나만 노출하는 것도 가능하다.
- 또 하나의 장점은, Sensors 내부의 자료구조가 Map이 아닌 다른 자료구조로 변경되더라도 외부에 변경이 발생하지 않아도 된다.
2. 경계 살피고 익히기
- 학습 테스트를 통해 외부 코드 사용 방법을 익힌다.
- 외부 코드가 변경될 경우 발생할 버그를 학습 테스트 코드를 통해 검증할 수 있다.
3. 학습 테스트는 공짜 이상이다.
- 학습 테스트에 드는 비용은 없다.
- 어쨌든 API를 배워야 하므로, 오히려 필요한 지식만 확보하는 손쉬운 방법이다.
- 학습 테스트는 이해를 높여주는 정확한 실험이다.
- 학습 테스트는 공짜 이상이다.
- 투자하는 노력보다 얻어지는 성과가 더 크다.
- 패키지의 새 버전이 나온다면, 학습 테스트를 돌려 차이가 있는지 확인한다.
✔️ 일급 컬렉션 (Frist Class Collection)
객체지향적으로, 리팩토링하기 쉬운 코드로 갈려면
일급 컬렉션이 필요하다.
💡 일급 콜렉션 사용
- 콜렉션을 포함한 클래스는 반드시 다른 멤버 변수가 없어야 한다.
- 각 콜렉션은 그 자체로 포장되어 있으므로, 이제 콜렉션과 관련된 동작은 근거지가 마련된셈이다.
- 필터가 이 새 클래스의 일부가 됨을 알 수 있다.
- 필터는 또한 스스로 함수 객체가 될 수 있다.
- 또한 새 클래스는 두 그룹을 같이 묶는다든가 그룹의 각 원소에 규칙을 적용하는 등의 동작을 처리할 수 있다.
- 이는 인스턴스 변수에 대한 규칙의 확실한 확장이지만, 그 자체를 위해서도 중요하다.
💡 일급 콜렉션 예제
Collection을 Wrapping하면서,
그 외의 다른 멤버 변수가 없는 상태이다.
Map<String, String> map = new HashMap<>();
map.put("1", "A");
map.put("2", "B");
map.put("3", "C");
이 코드를
public class Sensor {
// 멤버 변수가 하나밖에 없다!
private Map<String, String> sensors;
public Sensor(Map<String, String> sensors) {
this.sensors = sensors;
}
}
위와 같이 Wrapping 하는 것이다.
Collection을 Wrapping한다는 게 뭘까?
와닿지가 않는다.
또 다른 예제를 살펴보겠다.
public class Person {
private String name;
private List<Car> cars;
// ...
}
public class Car {
private String name;
private String oil;
// ...
}
이 코드를
public class Person {
private String name;
private Cars cars;
// ...
}
// List<Car> cars를 Wrapping
// 일급 컬렉션
public class Cars {
// 멤버변수가 하나 밖에 없다.
private List<Car> cars;
// ...
}
public class Car {
private String name;
private String oil;
// ...
}
이렇게 바꾸는 것이다.
💡 Wrapping을 왜 할까?
- 비지니스에 종속적인 자료구조
- Collection의 불변성을 보장
- final을 사용하면 안 될까?
- Java의 final은 불변을 만들어주는 것은 아니며, 재할당만 금지하는 것이다.
- Java에서는 final로 불변 문제를 해결할 수 없기 때문에, 일급 컬렉션과 래퍼 클래스 등의 방법으로 해결해야 한다.
- final을 사용하면 안 될까?
- 상태와 행위를 한 곳에서 관리
- 값과 로직이 함께 존재한다.
- 이름이 있는 컬렉션
- 컬렉션에 이름을 붙일 수 있다.
- 같은 OOO 기능들이라도, A 그룹의 OOO과 B 그룹의 OOO은 다릅니다.
- 구분은 각각의 일급 컬렉션을 만들면 된다!
아직은 좀 어렵고 와닿지 않은 개념들이다.
출처
- NextStep
- Clean Code 클린 코드 애자일 소프트웨어 장인 정신 / 로버트 C. 마틴 저
- https://jojoldu.tistory.com/412
- https://velog.io/@seongwon97/%EC%9D%BC%EA%B8%89-%EC%BB%AC%EB%A0%89%EC%85%98%EC%9D%B4%EB%9E%80
- https://tecoble.techcourse.co.kr/post/2020-05-08-First-Class-Collection/
'객제지향, TDD, 클린코드 > 클린코드' 카테고리의 다른 글
객체와 자료 구조 (0) | 2023.04.19 |
---|---|
클래스는 작아야 한다! (0) | 2023.03.22 |
깨끗한 테스트 코드 유지하기 (0) | 2023.03.17 |
함수는 한 가지만 해라 (0) | 2023.03.16 |
오류 코드보다 예외를 사용하라 (0) | 2023.03.08 |