이 영역을 누르면 첫 페이지로 이동
Arc 블로그의 첫 페이지로 이동

Arc

페이지 맨 위로 올라가기

[OOP] 원시 타입을 포장하라

Arc

[OOP] 원시 타입을 포장하라

  • 2023.03.15 17:36
  • Software Engineering/OOP
글 작성자: SeoArc

원시 타입

원시 타입(Primitive Type)은 알다시피 실제 데이터 값을 저장하는 타입으로 평소 많이 사용하는 형태이다. 원시 타입에는 보통 boolean, char, int, double 등 여러가지가 있다.

 

 

원시 타입을 포장하라?

원시 타입의 값을 객체로 포장하면 객체지향적으로 얻을 수 있는 이점들이 많다.

그럼 한 번 무엇이 있는지 살펴보자.

 

자신의 상태를 객체 스스로 관리할 수 있다

Wallet이라는 클래스에서, 사용자의 돈(cash)을 가지고 있다고 가정해보자.

public class Wallet {
private int cash;
public Wallet(int money) {
this.cash = cash;
}
}

위 형태처럼 원시 타입인 int로 돈을 가지고 있으면 어떨까?

 

일단 다음과 같이 나이에 관한 유효성 검사를 Wallet 클래스에서 하게 된다.

public class Wallet {
private int cash;
public Wallet(String cashValue) {
int cash = Integer.parseInt(cashValue);
if (cash < 0) {
throw new RuntimeException("돈은 0원 미만일 수 없습니다.");
}
this.cash = cash;
}
}

멤버 변수가 적어서 아직 문제를 못 느낄 수 있다. 하지만 다른 인스턴스 변수가 추가적으로 들어가 관리하게 된다면 문제가 생길 수 밖에 없다.

 

이름을 추가한 다음 코드를 살펴보자.

public class Wallet {
private String idCardNumber;
private int cash;
public Wallet(String idCardNumberValue, String cashValue) {
int cash = Integer.parseInt(cashValue);
validateCash(cash);
validateIdCardNumber(idCardNumberValue);
this.idCardNumber = idCardNumberValue;
this.cash = cash;
}
private void validateIdCardNumber(String idCardNumber) {
if (idCardNumber.length() < 13) {
throw new RuntimeException("주민번호는 13글자 이상이어야 합니다.");
}
}
private void validateCash(int cash) {
if (cash < 0) {
throw new RuntimeException("돈은 0원 미만일 수 없습니다.");
}
}
}

멤버 변수를 두 개 가졌을 뿐인데 Wallet 클래스가 할 일이 많아졌다. 그럼 한 번 원시 타입 변수를 포장해보자.

 

class IdCard {
private String idCardNumber;
public IdCard(String idCardNumber) {
if (idCardNumber.length() < 13) {
throw new RuntimeException("주민번호는 13글자 이상이어야 합니다.");
}
this.idCardNumber = idCardNumber;
}
}
class Money {
private int cash;
public Money(String cashValue) {
int cash = Integer.parseInt(cashValue);
if (cash < 0) {
throw new RuntimeException("돈은 0원 미만일 수 없습니다.");
}
this.cash = cash;
}
}
public class Wallet {
private IdCard idCard;
private Money money;
public Wallet(String idCardNumber, String cash) {
this.idCard = new IdCard(name);
this.money = new Money(cash);
}
}

이렇게 하면 주민번호와 돈의 처리를 각각 IdCard, Money가 담당하도록 바뀌었다.

유효성 검증을 비롯한 주민번호, 돈에 대한 상태 값을 Wallet에게 넘기지 않고 스스로 관리할 수 있게 되었다. 즉, 책임이 명확해졌다.

 

 

유지보수에 도움이 된다

먼저 다음 예시를 한 번 살펴보자.

다음은 로또와 로또 번호, 당첨 번호를 구성한 클래스들이다.

public class LottoNumber {
private final static int MIN_LOTTO_NUMBER = 1;
private final static int MAX_LOTTO_NUMBER = 45;
private final static String OUT_OF_RANGE = "로또번호는 1~45의 범위입니다.";
private final static Map<Integer, LottoNumber> NUMBERS = new HashMap<>();
private int lottoNumber;
static {
for (int i = MIN_LOTTO_NUMBER; i < MAX_LOTTO_NUMBER + 1; i++) {
NUMBERS.put(i, new LottoNumber(i));
}
}
public LottoNumber(int number) {
this.lottoNumber = number;
}
public static LottoNumber of(int number) {
LottoNumber lottoNumber = NUMBERS.get(number);
if (lottoNumber == null) {
throw new IllegalArgumentException(OUT_OF_RANGE);
}
return lottoNumber;
}
}
public class Lotto {
private List<LottoNumber> lottoNumbers;
public Lotto(List<LottoNumber> lottoNumbers) {
validateDuplication(lottoNumbers);
validateAmountOfNumbers(lottoNumbers);
this.lottoNumbers = lottoNumbers;
}
}
public class WinningNumber {
private Lotto winningLottoNumbers;
private int bonusNumber;
public WinningNumber(Lotto winningLottoNumbers, int bonusNumber) {
this.winningLottoNumbers = winningLottoNumbers;
if (isBonusNumberDuplicatedWithWinningNumber(winningLottoNumbers, bonusNumber)) {
throw new IllegalArgumentException(
BONUS_CANNOT_BE_DUPLICATE_WITH_WINNING_NUMBER);
}
if (bonusNumber < 1 | bonusNumber > 45) {
throw new RuntimeException();
}
this.bonusNumber = bonusNumber;
}
}

위 코드를 보면 로또 숫자를 LottoNumber로 래핑하여 사용하고 있는 것을 확인할 수 있다.

만약 이렇게 하지 않고 원시 타입(int)으로 사용했다면 각 로또 숫자에 대해 처리하는 행위가 추가되고 Lotto 클래스의 크기가 커질 것이다.

이렇게 되면 객체지향적으로 코드를 작성하기 힘들어진다.

 

또, 변경사항이 생긴다면 WinningNumber 클래스, Lotto 클래스 모두 수정해야 하는 상황이 생기게 된다.

때문에 저렇게 LottoNumber로 래핑해주면 변경과 확장에 열려있는 형태로 만들어줄 수 있다.

 

 

개별적으로 확장이 가능하다

위 Money 클래스에서 만약 cash이외의 값이 필요해졌다면 기존에 있는 money값을 수정할 필요 없이 다음과 같이 새로 추가하면 된다.

class Money {
private int cash;
private int giftCard;
public Money(String cashValue, String giftCardValue) {
int cash = Integer.parseInt(cashValue);
int giftCard = Integer.parseInt(giftCardValue);
if (cash < 0 || giftCard < 0) {
throw new RuntimeException("돈은 0원 미만일 수 없습니다.");
}
this.cash = cash;
this.giftCard = giftCard;
}
}
public class Score {
private int score;
private double percentScore;
public Score(int score) {
validateScore(score);
this.score = score;
}
public Score(double score) {
validateScore(score);
this.percentScore = score / 100.0;
}
}

이렇게 인스턴스 변수를 간단히 새로 추가하고 관리할 수 있게 된다.

'Software Engineering > OOP' 카테고리의 다른 글

[OOP] 무분별한 Getter/Setter를 지양하라  (0) 2023.03.16
[OOP] 상속보다는 조합을 사용하자  (0) 2023.03.15
[OOP] instanceof의 사용을 지양하라  (0) 2023.03.14

댓글

댓글을 사용할 수 없습니다.

이 글 공유하기

  • 구독하기

    구독하기

  • 카카오톡

    카카오톡

  • 라인

    라인

  • 트위터

    트위터

  • Facebook

    Facebook

  • 카카오스토리

    카카오스토리

  • 밴드

    밴드

  • 네이버 블로그

    네이버 블로그

  • Pocket

    Pocket

  • Evernote

    Evernote

다른 글

  • [OOP] 무분별한 Getter/Setter를 지양하라

    [OOP] 무분별한 Getter/Setter를 지양하라

    2023.03.16
  • [OOP] 상속보다는 조합을 사용하자

    [OOP] 상속보다는 조합을 사용하자

    2023.03.15
  • [OOP] instanceof의 사용을 지양하라

    [OOP] instanceof의 사용을 지양하라

    2023.03.14
다른 글 더 둘러보기

정보

Arc 블로그의 첫 페이지로 이동

Arc

  • Arc의 첫 페이지로 이동

검색

메뉴

  • 홈
  • 태그
  • 방명록

카테고리

  • 분류 전체보기 (106)
    • Language (28)
      • C++ (0)
      • C# (0)
      • Java (28)
    • Algorithm (47)
      • Algorithm (15)
      • Data Structure (6)
      • PS (26)
    • Computer Science (22)
      • Design Pattern (1)
      • Network (14)
      • OS (7)
    • Game (0)
      • Unity (0)
    • Backend (3)
      • Spring (1)
      • JPA (2)
    • DB (0)
      • SQL (0)
    • DevOps (2)
      • AWS (0)
      • Docker (2)
      • Jenkins (0)
      • Nginx (0)
    • Software Engineering (4)
      • OOP (4)
    • AI (0)
      • Machine Learning (0)
    • Others (0)

인기 글

공지사항

태그

  • 네트워크
  • 그래프
  • graph
  • 알고리즘
  • algorithm
  • java
  • network
  • 자바

정보

SeoArc의 Arc

Arc

SeoArc

블로그 구독하기

  • 구독하기
  • RSS 피드

방문자

  • 전체 방문자
  • 오늘
  • 어제

티스토리

  • 티스토리 홈
  • 이 블로그 관리하기
  • 글쓰기
Powered by Tistory / Kakao. © SeoArc. Designed by Fraccino.

티스토리툴바

개인정보

  • 티스토리 홈
  • 포럼
  • 로그인

단축키

내 블로그

내 블로그 - 관리자 홈 전환
Q
Q
새 글 쓰기
W
W

블로그 게시글

글 수정 (권한 있는 경우)
E
E
댓글 영역으로 이동
C
C

모든 영역

이 페이지의 URL 복사
S
S
맨 위로 이동
T
T
티스토리 홈 이동
H
H
단축키 안내
Shift + /
⇧ + /

* 단축키는 한글/영문 대소문자로 이용 가능하며, 티스토리 기본 도메인에서만 동작합니다.