안드로이드 Pair 클래스의 이점에 대해서..

안드로이드 API를 살펴보다 보면 Pair 클래스라는 것을 볼 수 있다. 이 클래스는 안드로이드의 java.util 패키지 그리고 android.support.v4.util 패키지에서 확인할 수 있다. 이 클래스들의 소스를 확인해 보면 같은 구현체라는 것을 알 수 있다.

API 문서의 설명을 보면 “두 객체의 튜플을 다른 객체에 전달하기 쉽게 사용하는 컨테이너”라고 정의한다. 이 클래스는 C++(http://www.cplusplus.com/reference/utility/pair/), 자바는 외부 라이브러리인 아파치 Common Lang 패키지(org.apache.commons.lang3.tuple.Pair<L,R>), 그리고 C#의 경우 Tuple 이나 KeyValuePair(http://www.dotnetperls.com/tuple-keyvaluepair) 클래스가 같은 기능을 제공하고 있다.

이 글에서는 Pair 클래스를 사용해서, 어느 부분에 사용하면 좋은지 그리고 이 클래스를 사용해서 기존 코드보다 조금 더 간결한 코드를 만들 수 있는 방안에 대해 살펴보자.

1. I/O(네트워크 등) 요청의 응답 처리

많은 안드로이드 앱이 로직을 처리하기 위해서 네트워크로 데이터를 요청하고 수신한다. 종종 네트워크로 데이터 목록을 요청하는 경우 다음과 같은 코드를 사용하는 경우를 볼 수 있다. 아래에서 사용자 신용카드 목록을 가져오는 로직을 예로 살펴보자.

public ArrayList<CreditCard> getCreditCards() {
    ...
    ...
}

이 메서드를 호출하는 객체가 반환받을 수 있는 결과의 경우 수는 null 또는 ArrayList<CreditCard>의 결과가 될 것이다. 그리고 Activity나 Fragment에서 호출해서 받은 결과가 null 이면, “알수 없는 에러” 또는 “에러가 발생했으니 좀 있다가 다시 해라“등의 모호한 에러 메시지를 전달하게 되는 경우를 쉽게 볼 수 있다.

그래서, 위 문제를 개선하기 위해서 모델(Model) 클래스에 에러코드를 포함하는 형태를 취하는 경우도 종종 볼 수 있다.

public CreditCardsModel {
     int errorCode;
     ArrayList<CreditCard> creditCards;
     ...
     ...
}

public CreditCardsModel getCreditCards() {
     ...
     ...
}

결국 이 상황은 래퍼 모델(Wrapper Model)의 추가하게 해서 불 필요한 클래스를 생성하게 한다. 그래서 위 래퍼 모델을 생성하지 않고도 쉽게 모델로 처리할 수 있는 방법으로 Pair 클래스를 사용할 수 있다.

/**
* Created by mcsong on 10/22/15.
*/
public class GetCreditCardImpl {

    public static GetCreditCardImpl newInstance() {
        return new GetCreditCardImpl();
    }

    public Pair<Integer , ArrayList< CreditCard>> getCreditCards() throws Exception {
        ArrayList <CreditCard> creditCards = new ArrayList<>() ;

        String rUrl = ".........................../data.json" ;

        Pair <Integer, String> responseValue = HttpRequest. doGetString( rUrl);
        if (responseValue == null)
            return Pair.create( HttpConstant.RETURN_CODE_ERROR, creditCards);

        if (responseValue. first != 200 )
            return Pair.create( responseValue.first , creditCards) ;

        JSONObject jObject = new JSONObject(responseValue. second);
        JSONArray jArray = jObject .getJSONArray( "results");

        for (int i = 0; i < jArray .length() ; i++ ) {
            creditCards .add( CreditCard.parse( jArray.getJSONObject (i))) ;
        }

        return Pair.create( responseValue.first , creditCards) ;
    }

}

이 클래스는 신용카드 목록을 가져오는 구현(Impl)클래스이고, getCreditCards() 메서드에서 사용자의 신용카드 목록을 요청(Http 요청)하고, 받은 결과를 Pair<Integer, String> 객체에 담아서, 이 객체의 결과로 받은 결과(Json 문자열)를 앱이 사용하는 모델로 변경(CreditCard)해서 전달하고 있다.
이 소스로 결과 코드를 처리하기 위해서 사용했던 CreditCardsModel을 사용하지 않고 기존에 CreditCard 모델만 사용해서 목록을 온전히(에러 코드에 따른 상황 처리 포함) 처리할 수 있다.

아래 이미지는 개인적으로 자바나 안드로이드 프로젝트를 하면서 로직을 처리하는 기본 구조로 사용하는 간단한 클래스 다이어그램이다.
logic_uml
이 예에서 알 수 있는 것은, 로직을 처리하는 클래스에서 Pair 객체를 사용하면 기존에 사용하던 형태보다 비교적 간결한 형태로 로직을 구현할 수 있다는 것이다.

2. 한 번에 두 개 이상의 결과 처리

자바는 기본으로 반환 결과를 2개 이상 제공하지 않는다. 그래서 2개 이상의 결과를 반환받기 위해서는 객체나 배열의 형태를 보이게 된다. 그중에 2개의 결과가 필요한 경우를 종종 볼 수 있다. 자바와 가장 비슷하다는 C#의 경우에는 이미 out 키워드를 제공해서 두 개 이상의 결과를 쉽게 처리할 수 있다.

이 상황의 간단한 예제로 2개의 숫자를 입력받아서, 입력받은 숫자 중에 하나로 다른 입력값을 나눈 몫과 나머지가 필요하고, 몫과 나머지는 인캡슐되어 있는 클래스가 제공한다고 가정해 보자. 이 상황에서는 일반적으로 몫을 가져오는 메서드, 나머지를 가져오는 메서드 2개를 호출해서 구현하게 된다. 이런 형태를 구현하는 예제를 살펴보자.

public static Pair<Integer , Integer> divide(int src1 , int src2 ) {
    int v1 = src1 /src2;
    int v2 = src1 % src2;

    return Pair.create( v1, v2 );
}

위 소스는 src1을 src2로 나눈 결과(몫과 나머지)를 한꺼번에 반환하는 메서드이다.
Pair <Integer, Integer> result = divide( 5, 2 );
result.first : 몫
result.second : 나머지
위 예제는 divide() 메서드를 호출해서 받은 결과를 사용하는 예를 보여준다.

이 글에서 Pair를 사용해서 기존 코드보다 간결하게 로직을 처리하는 형태와 한 번에 두 개 이상의 결과를 처리하는 형태를 살펴봤다. 이 클래스는 가뜩이나 장황(verbose)하다는 자바의 코드를 약간 이나마 간결하게 사용할 수 있게 도움을 줄 수 있기에 잘 사용하면 코드를 개발하고 유지보수 하는 데 많은 도움을 줄 수 있겠다.

안드로이드 Pair 클래스의 이점에 대해서..”에 대한 2개의 생각

답글 남기기

이메일은 공개되지 않습니다. 필수 입력창은 * 로 표시되어 있습니다.