'pattern'에 해당되는 글 3건

  1. 2015.01.27 [pattern 04] 빌더 패턴 1
  2. 2015.01.26 [pattern 03] 자바빈 패턴
  3. 2015.01.15 [pattern 01] ViewHolder pattern- (1) 1
2015. 1. 27. 01:20




[Android pattern 02] 에서의 안정성과 [Android pattern 03] 에서의 가독성을 결합한 새로운 대안이 바로 빌더 패턴이다. 필수 인자를 포함한 빌더객체를 생성하고 선택인자들을 빌더객체에 추가완료한 후에 빌더객체를 통해 원하는 생성자의 객체를 생성한다. 이렇게 하여 만든 생성자의 객체는 변경 불가능(immutable) 객체이다. 설명만 들어서는 이해하기 힘드니 코드를 살펴보자.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
public class NutritionFacts {
    private final int servingSize;                    // 필수
    private final int servings;                         // 필수
    private final int calories;                          // 선택
    private final int fat;                                  // 선택
    private final int sodium;                           // 선택
    private final int carbohydrate;                 // 선택
 
    public static class Builder {
        //    필수 인자
        private final int servingSize;
        private final int servings;    
        //    선택적 인자
        private int calories = 0;                    //기본값으로 초기화
        private int fat = 0;    
        private int sodium = 0;
        private int carbohydrate = 0;
 
        public Builder ( int servingSize, int servings ) {
            this.servingSize = servingSize;
            this.servings = servings;
        }
 
        public Builder calories( int val ) { 
            calories = val;
            return this;
        }
 
        public Builder fat( int val ) { 
            fat = val;
            return this;
        }
 
        public Builder sodium( int val ) { 
            sodium = val;
            return this;
        }
 
        public Builder carbohydrate( int val ) { 
            carbohydrate = val;
            return this;
        }
 
        public NutritionFacts build() {
            return new NutritionFacts( this );
        }
    }
 
    private NutritionFacts( Builder builder ) { 
        servingSize = builder.servingSize;
        servings = builder.servings;
        calories = builder.calories;
        fat = builder.fat;
        sodium = builder.sodium;
        carbohydrate = builder.carbohydrate;
    }
}
cs


NutritionFacts  의 객체는 변경불가능 하고 빌더에 정의되어 있는 setter 메소드들은 빌더 객체 자신을 반환하므로, 설정메소드를 호출하는 코드는 죽 이어서 쓸 수 있다.


1
2
3
4
5
6
7
8
 
NutritionFacts cocaCola = 
        new NutritionFacts().Builder( 2408)
                        .calories( 100 )
                        .sodium ( 35 )
                        .carbohydrate( 27 )
                        .build();
 
cs


빌더패턴은 코드의 가독성도 뛰어나고 사용하기도 쉽다.다만 코드 사용량이 점층적 생성자 패턴 등보다는 많으므로 인자가 충분히 많은 상황에서 이용해야하는게 옳다. 물론 새로운 인자가 추가될 수도 있다는 것을 고려해서 사용하는 방법도 괜찮다.


<참고서적 : Effective Java 2/E>

Posted by 미뤽
2015. 1. 26. 22:19



생성자에 전달하는 인자수가 많은 때 점층적 생성자 패턴과 함께 적용가능한 두번째 패턴은 자바빈 패턴이다.인자가 없는 생성자를 통해 객체를 만든 후, 설정 메서드들을 호출하여 필수, 선택 필드들을 채우는 방법이다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class NutritionFacts {
    private int servingSize = -1;              // 필수
    private int servings = -1;                   // 필수
    private int calories = 0;                     // 선택
    private int fat = 0;                             // 선택
    private int sodium = 0;                      // 선택
    private int carbohydrate = 0;             // 선택
 
    public NutritionFacts() { }
 
    //    setter
    public void setServingSize( int val ) { servingSize = val; }
    public void setServings( int val ) { servings = val; }
    public void setCalories( int val ) { calories = val; }
    public void setFat( int val ) { fat = val; }
    public void setSodium( int val ) { sodium = val; }
    public void setCarbohydrate( int val ) { carbohydrate = val; }
}
cs



위 코드를 통해 생성자 객체를 생성하고 인자를 넣는 방법은


1
2
3
4
5
6
NutritionFacts cocaCola = new NutritionFacts();
cocaCola.setServingSize( 240 );
cocaCola.setServings( 8 );
cocaCola.setCalories( 100 );
cocaCola.setSodium( 35 );
cocaCola.setCarbohydrate( 27 );
cs


이 패턴은 점층적 생성자 패턴과는 다르게 읽기도 쉽고 생성하기도 좋다. 하지만 이 패턴에는 두가지 심각한 단점이 있는데, 첫번째는 1회의 함수 호출로 객체 생성을 끝낼 수 없으므로, 객체 일관성(consistency)이 일시적으로 깨질 수 있다는 점이고 두번재는 자바빈 패턴으로는 변경 불가능(immutable)클래스를 만들 수 없다는 것이다.


<참고서적 : Effective Java 2/E>


Posted by 미뤽
2015. 1. 15. 02:21



안드로이드를 개발하면서 가장 많이 사용하는 기능 중 하나가 ListView라고 생각한다. ListView를 사용할 때 잘 모르는 상태에서 무의식 적으로 따라 사용하던 패턴이 있었는데 바로 ViewHolder 패턴이다. (사실 패턴인지도 몰랐었다.) 안드로이드를 처음 접했을때는 Adapter라는 개념도 생소했기 때문에 구현하는 방식의 일부라는 생각에 무의식 적으로 사용해 왔던 것 같다. 이번에 기회가 되서 ViewHolder pattern에 대해 조금 알아보기로 했다. 그러기 위해서는 ListView에 대해서 먼저 알아보자.


ListView는 이름 그대로 내가 보여주고자 하는 데이터들의 리스트를 보여주는 View이다. 하지만 내가 보여주고자 하는 100개, 1000개의 데이터들을 hierarchy에 올려놓고 순서대로 보여주려다가는 느려서 스크롤도 하기 힘들것이다. 이를 해결해 주기 위해서 ListView는 getView()라는 녀석을 사용한다. 정확히는 getView() 메소드에서 사용하는 convertView를 사용한다. convertView는 ListView를 효과적으로 사용하기 위해서 1) adapter에 여러 타입의 data들이 있을때 자동으로 convertView는 해당 타입이 될 것이고 2) 재사용을 할 수 있다. 세가지의 예를 한번 살펴보자.


첫번째는 "느린 방법"이다.

1
2
3
4
5
6
7
8
9
public View getView(int position, View convertView, ViewGroup parent) {
    View item = mInflater.inflate(R.layout.list_item, null);
 
    ((TextView) item.findViewById(R.id.text)).setText(DATA[position]);
    ((ImageView) item.findViewById(R.id.icon)).setImageBitmap(
                (position & 1 ) == 1 ? mIcon1 : mIcon2);
 
    return item;
}
cs


이 방법은 getView()가 리스트의 하나의 아이템을 나타낸다는 것을 알았을때 구현하는 가장 기본적인 방법이다. 이 방법은 getView()가 호출될 때 마다 새로운 View를 생성한다. 또한, 2행에서 XML을 inflating하는 작업은 안드로이드에서 무거운 작업이다. 특히나 위의 코드 예제와 같이 ImageView를 사용할 경우 만약 100개, 1000개의 리스트 아이템을 보여줄 경우 그만큼의 infalting작업과 View 생성 작업을 해야 한다는 단점이 있다.(하나의 view는 Ram에서 1kilobytes,2kilobytes를 차지한다.) 아이템이 많아질 수록 앱의 동작은 느려지거나 끊기게 된다. 이를 고치기 위해서는 convertView를 사용하면 된다.


두번째 "올바른 방법"

1
2
3
4
5
6
7
8
9
10
11
12
public View getView(int position, View convertView, ViewGroup parent) {
    if (convertView == null) {
        convertView = mInflater.inflate(R.layout.list_item, parent, false);
    }
 
    ((TextView) convertView.findViewById(R.id.text)).setText(DATA[position]);
    ((ImageView) convertView.findViewById(R.id.icon)).setImageBitmap(
                (position & 1 ) == 1 ? mIcon1 : mIcon2);
 
    return convertView;
}
 
cs


아까 위에서 언급했듯이 convertView는 재사용이 가능하도록 설계되어있기 때문에 infalating작업을 했던 아이템들에 대해서는 null체크를 통해 해당 작업을 생략하는 방법을 사용한다. 이 방법을 사용하면 아이템의 총 갯수에 관계없이 화면에 맞는 갯수의 아이템(view)을 ListView가 할당한다.(1,2개 더 할 수도 있다.) 즉, 100개의 리스트 아이템때문에 느려질 걱정은 하지 않아도 된다. 마지막으로 살펴볼 방법이 오늘 내가 이야기 하고자 하는 ViewHolder를 이용하는 방법이다.


마지막 "빠른 방법"


ViewHolder pattern은 작은 data저장소를 만들어 각각 리스트 아이템들을 static으로 연결하는 것이다. 예제를 보면 두번째 방법을 통해 inflating하는 작업은 줄였지만 TextView와 ImageView를 가져오기 위해 매번 findViewById 작업을 반복하고 있다. ViewHolder pattern을 사용하면 한번 연결한 데이터는 저장소에 저장하여 다시 findViewById를 통해 view를 찾아올 필요가 없다. 


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
 
public View getView(int position, View convertView, ViewGroup parent) {
    ViewHolder holder;
 
    if (convertView == null) {
        convertView = mInflater.inflate(R.layout.list_item, parent, false);
        holder = new ViewHolder();
        holder.text = (TextView) convertView.findViewById(R.id.text);
        holder.icon = (ImageView) convertView.findViewById(R.id.icon);
 
        convertView.setTag(holder);
    } else {
        holder = (ViewHolder) convertView.getTag();
    }
 
    holder.text.setText(DATA[position]);
    holder.icon.setImageBitmap(
                (position & 1 ) == 1 ? mIcon1 : mIcon2);
 
    return convertView;
}
cs


ViewHold는 필요한 곳에서 생성해 주면 된다.


1
2
3
4
5
static class ViewHolder {
    TextView text;
    ImageView icon;
}
 
cs



참고자료 - Google I/O 2010 - The world of ListView


Posted by 미뤽