원시타입을 `Wrapper Class`로 포장해서 객체로 만듦 원시타입의 값을 이용해 속성을 표현하지 않고 , 의미가 있는 객체로 표현 클래스 내부에 검증 로직을 만들어 `스스로 상태를 관리하게 되어 책임을 분리`
블로그 여러개 보면서 원시값 포장
을 어디에 사용하는건가 고민하고 있었는데 우테코 2기 오렌지 원시값 포장 이 글을 보고 어디에 쓸 지 감이 잡혔다.
원시값을 클래스에 넣어서 사용하게 되면 그 클래스에서는 어떠한 동작만 하고 싶은데 변수들을 관리하느라 자잘한 메소드들이 생겨나게 된다. 그러면 클래스가 길어지게 되고 가독성이 안좋아지게 된다.
그리고 이런식으로 코드를 짜게 되면 유지보수가 쉬워지고, 값의 유효성 검증을 하기 편해진다.
자 그럼 원시값 포장
을 알아보기에 앞서 먼저 원시타입
에 대해서 알아보자
자바에는 원시타입
과 참조타입
두가지의 타입이 있다.
정수, 실수, 문자, 논리 리터럴(boolean) 등 실제 데이터 값을 저장하는 타입
기본 타입을 제외한 타입으로, 객체의 주소를 저장하는 타입 → 문자열, 배열, 열거형 상수, 클래스, 인터페이스 등
이렇게 보면참조타입
과 비교해서 장점이 없어 보이는데 원시타입
을 왜 사용할까?
이제 코드로 살펴보자!
public class Mouse {
private String name; // 쥐의 이름
private int age; // 쥐의 나이
public Mouse(String name, int age){
validateName(name);
validateAge(age);
this.name = name;
this.age = age;
}
private void validateName(String name) {
if (name.length() < 2) {
throw new RuntimeException("이름은 두 글자 이상이어야 합니다.");
}
}
private void validateAge(int age) {
if (age < 1) {
throw new RuntimeException("나이는 0살부터 시작합니다.");
}
}
public void printNameAge(){
System.out.println(name + " " + age);
}
}
Mouse
라는 클래스를 만들어줬다. 클래스 이름이 Mouse
인 이유는 이번에 알고리즘 팀플하는데 쥐가 미로찾기하는 프로그램 만드는 거라서 그렇게 지었다. → 아무의미 없음
아무튼 이 코드는 이름과 나이를 private
점근제어자를 써서 원시값 형태로 가지고 있다. 이렇게 되면 원래 Mouse
클래스에는 쥐가 가진 동작들을 넣어야 하는데 name
과 age
를 관리할 메소드까지 넣어야해서 클래스가 길어지게 된다.
그래서 이 원시값들을 객체로 관리해보자
public class Mouse {
private Name name;
private Age age;
public Mouse(String name, int age) {
this.name = new Name(name);
this.age = new Age(age);
}
public void printNameAge() {
System.out.println(this.name + " " + this.age);
}
}
class Name {
private String name; // 쥐의 이름
public Name(String name) {
if (name.length() < 2) {
throw new RuntimeException("이름은 두 글자 이상이어야 합니다.");
}
this.name = name;
}
}
class Age {
private int age; // 쥐의 나이
public Age(int age) {
if (age < 1) {
throw new RuntimeException("나이는 0살부터 시작합니다.");
}
this.age = age;
}
}
클래스를 나눠서 Name
클래스와 Age
클래스로 각 변수들의 유효성 검사를 해주고 Mouse
클래스에서는 출력만 담당하게 해줬다.
이렇게 하면 훨씬 코드가 보기 편하다.
원시타입을 객체로 포장한것
Wrapper Class
에는 Null값을 넣을 수 있다. 원시타입
은 당연히 안된다. 그리고 객체이다 보니 ==
이 아닌 .equals()
메소드로 값 비교를 한다. 만약 ==
을 사용하게 된다면 값
이 아닌 주소
를 비교하게 되므로 false
가 반환된다!
그렇다면 이 Wrapper Class
를 언제 사용할까?
제네릭<>
이 들어가면 필수로 Wrapper Class
를 사용해야 한다고 한다. → ArrayList, LinkedList 등에 쓰인다.
저번에 썼을때는 모르고 썼는데 하나 배웠다..
ArrayList<Integer> arr = new ArrayList<>(); // 올바른 형식
ArrayList<int> arr = new ArrayList<>(); // 잘못된 형식
위에서 말했듯이 원시타입
에는 byte
, short
, int
, long
, float
, double
, boolean
, char
이 있다.
그리고 Wrapper Class
에는 Byte
, Short
, Integer
, Long
, Float
, Double
, Boolean
, Character
이 있다. 그냥 원시타입에 대문자만 붙인 느낌이다. Integer
랑 Character
제외!!
값으로 쓰일 수 있는 객체 객체의 불변성 보장 로직 포함 가능
equals()
와 hashcode()
를 오버라이딩 → 재정의해야함!
VO
관련해서 찾다보니 DTO
와 Entity
라는 개념이 나온다 나중에 조사해서 글을 써보자
그리고 MVC 패턴
들도 자주 보이는데 이것도 조사해서 글을 써봐야겠다.
내가 이해한 바로는 VO
도 원시값 포장에 속하기는 하는데 더 좁은 의미인것 같다. 불변성을 갖기 때문에 set
을 하지 못하고 메서드들도 재정의 해주어야 한다.
둘 다 도메인 객체
를 포장하기 위해 사용하는 것은 같다. 음.. 이건 코드를 많이 짜보면서 익숙해져야할 것 같다..
알아보면서 뭔가 배운다는 느낌은 좋은데 어렵다.. 공부를 하면 할수록 알아야할게 많아지고 있다..... 그래도 알아가는 재미는 있다. 좀 더 재미를 붙여보자!!!!!
https://siyoon210.tistory.com/139
https://tecoble.techcourse.co.kr/post/2020-05-29-wrap-primitive-type/
https://wildeveloperetrain.tistory.com/12
https://velog.io/@myspy/%EC%9B%90%EC%8B%9C%EA%B0%92-%ED%8F%AC%EC%9E%A5VO