[Java] 원시값을 포장한다? 일급 컬렉션?

별의개발자커비·2023년 9월 9일
0

Java

목록 보기
65/66
post-thumbnail

개요

스터디를 진행하다 원시값을 포장하고, 일급 컬렉션을 사용해야할 것 같다는 피드백을 받았다. 원시값 포장, 일급 컬렉션... 들어는 봤는데 정확히 그게 뭐지? 객체지향에 관련하여 이런 데에서 기초가 부족함을 다시 한 번 느낀다. 내가 이해한 대로 정리해보자!

참고글

원시값을 포장한다?

객체지향 체조 원칙에 모든 원시값과 문자열을 포장하라 가 있다.
여기서 원시값을 포장한다라는 게 무슨 뜻일까?

우선 원시값이란,

원시 타입(Primitive Type)의 변수를 이야기하는데,
원시타입은 정수, 실수, 문자, 논리 리터럴등의 실제 데이터 값을 저장하는 타입을 말한다. boolean, char, int 등 ( String은 원시자료형처럼 쓰이는 참조 타입)

원시값 포장 전

나이age 속성을 그냥 원시타입int의 멤버변수로 선언했다.

public class Student {
	private int age;
    
    public Student(int age) {
    this.age = age;
    }
}

이 경우 age에 대해 validate를 해야한다고 했을 때 이 Student 클래스에서 유효성 검사를 해야한다.
만약 속성이 age 이외에 이름, 주소, 성적 등등 늘어난다고 했을 때 각 속성별 validate 관리가 어렵다.
이렇게 되면 Student 클래스는 Student 관리 역할만 하는 게 아니라, 각 속성별 관리를 해줘야하는, 역할 분담이 애매해지는 문제가 발생한다.

원시값 포장 후

나이age 속성을 그냥 원시타입int의 멤버변수로 선언하지 않고,
멤버변수를 자신의 속성(int age) 하나만 갖는 Age 객체로 일급 컬렉션을 만들어줬다.
그렇게 되면, 나이에 대한 유효성 검사도 Student 클래스가 아닌 Age 클래스에 위임해줄 수 있다.
역할 분담이 명확하게 되었다고 할 수 있다.

public class Student {
	private Age age;
   
   public Student(string age) {
   this.age = new Age(age);
   }
} 

public class Age {
	private int age;
   
   public Age(String input) {
   this.age = Integer.parseInt(input);
   if(age < 0) {
           throw new RuntimeException("오류: 0보다 작은 나이");
       }
   }
}

일급 컬렉션이란?(First Class Collection)

간단히 말해, 어떤 객체에 멤버 변수가 하나 밖에 없는 상태를 이야기한다.

List<String, String> studentList = new arrayList<>();
studentList.add("a");
studentList.add("b");
studentList.add("c");

위 코드를 아래처럼 Wrapping하는 것을 말한다.

public class Students {
	private List<String> studentList;
    
    public Fruits(List<String> studentList) {
    this.studentList = studentList;
    }
}

Collection(list, map 등)을 Wrapping해서, 다른 멤버 변수가 없는 상태가 되는 걸 이야기한다.

// 내 이해를 돕기 위해 적기...
아아 student들이 여러명 있는 list<Student>로 관리할 수도 있지만 그렇게하지 않고 그 자체의 객체를 만든 것을 말하는 건가? 
Students의 생성자 using Field느낌으로 List<String> studentList를 그 객체의 유일한 멤버변수(= 나자신)으로 쓰는 것을 말하는 느낌이다!

왜 일급 컬렉션을 써야할까?

비지니스에 종속적인 자료구조
Collection의 불변성을 보장
상태와 행위를 한 곳에서 관리
이름이 있는 컬렉션

이 네가지가 장점으로 꼽히는데 하나씩 이해해봐야겠다.

우선 이해하기로는, 객체지향, 리팩토링의 문제가 가장 많이 언급되는 것 같다.

1. 비지니스에 종속적인 자료구조

이름 길이 검증, 중복 검증 등의 로직을 생성자에 넣음으로써 Student의 list에 관련된 로직은 Students에 묶는다.가 된다.

public class Students {
    private List<Student> studentList;

    public Fruits(List<Student> studentList) {
        validateStudentName(studentList);
        validateDuplicateStudent(studentList);
        this.studentList = studentList;
    }
    ...
}

2. Collection의 불변성을 보장

Students 즉, studentList의 재할당은 불가능하다. getter, setter가 따로 없이 내부 값의 변경이 불가능하게 되어있는 특징을 보인다.

final과의 차이

final은 재할당(new ~)만 안되지 put, set 다 가능한다.

3. 상태와 행위를 한 곳에서 관리

Students에 관련해서 처리할 때 여러 학교의 studentList의 평균 점수를 내려고 한다면 여러개의, 아무곳에나 평균 점수 구하기 메소드를 만드는 게 아니라 해당 메소드를 일급 컬렉션인 Student 안에 만들어 호출해서 쓰면 Students라는 상태와 students의 평균 점수를 구하는 행위를 한 곳에서 관리할 수 있다.

또 위의 validateDuplicateStudent 같은 검증을 예를들어 메인로직에서 하고, valid 로직에서 또 하고 이렇게 중복되지 않게 일급컬렉션 내에만 존재시켜서 실행시키게 할 수 있다.

4. 이름이 있는 컬렉션

List<Student> middleSchool = new ArrayList<>();
List<Student> highSchool = new ArrayList<>();

위 방식을 아래 처럼 관리했을 때,

MiddleSchool middleSchool = new MiddleSchool();
HighSchool highSchool = new HighSchool<>();

이렇게 이름을 만들어 일급컬렉션을 사용하면 다른 사람이 봤을 때에도 위 변수들을 이해하기가 쉬워진다.

회고

사실 원시값을 포장한다 = 속성이 여러개이면 객체화해서 쓴다. 라고 이해했는데 절반만, 아니 어떻게 보면 잘못 이해하고 있었다고 볼 수 있다. 당장 풀어야하는 문제들에 치여 대충 이해하고 넘어갔던 것 같은데, 시간 내어서 찾아보고 정리하니 이제서야 제대로 이해가 가고, 또 어떻게 코드를 개선할 수 있을지 감이 잡힌다.

객체지향이 뭔지 계속해서 알아가는 과정에 있는데 어떤 걸 찾아봐야하나 하는 생각이 들었었다. 돌아보니 객체지향 체조 원칙부터, 그냥 아 저 원칙들을 따라야겠다가 아니라 하나 하나 원칙들이 뭔지 제대로 알고, 왜 써야하는지를 쫓다보면 자연스레 객체지향에 가까워질 수 있을 것 같다는 생각이 들었다! 새로운 공부 방향 겟!

0개의 댓글