|
| 1 | +# 어댑터 패턴 |
| 2 | + |
| 3 | +## 📌 어댑터 패턴이란? |
| 4 | + |
| 5 | +- 호환성이 없는 기존 클래스의 인터페이스를 변환하여 사용자가 기대하는 인터페이스 형태로 변환시키는 패턴이다. |
| 6 | + - 예) 전기 플러그 → 나라마다 서로 다른 플러그의 경우 어댑터를 사용하여 변환시킬 수 있다. |
| 7 | + |
| 8 | +  |
| 9 | + |
| 10 | +- 코드의 재활용성이 증가하고 기존의 코드를 수정하지 않아도 된다는 장점이 있다. |
| 11 | + |
| 12 | +## 📌 언제 사용할까? |
| 13 | + |
| 14 | +- 외부 구성요소를 기존 시스템에서 재사용하고 싶지만 호환되지 않는 경우에 사용한다. |
| 15 | +- 애플리케이션이 클라이언트가 기대하는 인터페이스와 호환되지 않는 경우에 사용한다. |
| 16 | +- 원본 코드를 수정하지 않고 애플리케이션에서 레거시 코드를 재사용하려는 경우에 사용한다. |
| 17 | + |
| 18 | +## 📌 어댑터 패턴의 요소 |
| 19 | + |
| 20 | +- 문제 상황 : 사용 객체의 API가 서로 다르다. |
| 21 | +- 해결 방안 : 함수를 변환하는 객체를 중간에 넣는다. |
| 22 | +- 결과 : 변경을 최소화 한다. |
| 23 | +- 예시 |
| 24 | + - 가정1 : 기존 소프트웨어 시스템에서 새로운 업체에서 제공한 클래스 라이브러리를 사용해야한다. |
| 25 | + |
| 26 | +  |
| 27 | + |
| 28 | + 해결방안 : 기존 코드를 바꿀 수 없다면 업체에서 사용하는 인터페이스를 기존에 사용하던 인터페이스에 적용시켜주는 클래스를 만들어 사용한다. 이 경우 어댑터는 클라이언트로부터 요청을 받아서 업체에서 제공하는 클래스에서 수용할 수 있는 형태로 변환시켜주는 중개인 역할을 한다. |
| 29 | + |
| 30 | +  |
| 31 | + |
| 32 | + |
| 33 | +## 📌 [예시 1] 오리의 탈을 쓴 칠면조 |
| 34 | + |
| 35 | +### Duck interface & Mallard Duck class |
| 36 | + |
| 37 | +```java |
| 38 | +public interface Duck { |
| 39 | + public void quack(); |
| 40 | + public void fly(); |
| 41 | +} |
| 42 | + |
| 43 | +public class MallardDuck implements Duck { |
| 44 | + public void quack() { |
| 45 | + System.out.println("Quack"); |
| 46 | + } |
| 47 | + public void fly() { |
| 48 | + System.out.println("I'm flying"); |
| 49 | + } |
| 50 | +} |
| 51 | +``` |
| 52 | + |
| 53 | +### Turkey interface & WildTurkey class |
| 54 | + |
| 55 | +```java |
| 56 | +public interface Turkey { |
| 57 | + public void gobble(); |
| 58 | + public void fly(); |
| 59 | +} |
| 60 | + |
| 61 | +public class WildTurkey implements Turkey { |
| 62 | + public void gobble() { |
| 63 | + System.out.println("Gobble gobble"); |
| 64 | + } |
| 65 | + public void fly() { |
| 66 | + System.out.println("I'm flying a short distance"); |
| 67 | + } |
| 68 | +} |
| 69 | +``` |
| 70 | + |
| 71 | +**Duck 객체가 모자라서 Turkey 객체를 대신 사용해야하는 상황에서 어떻게 어댑터를 구현할 수 있을까?** |
| 72 | + |
| 73 | +```java |
| 74 | +public class TurkeyAdapter implements Duck { |
| 75 | + Turkey turkey; |
| 76 | + public TurkeyAdapter(Turkey turkey) { |
| 77 | + this.turkey = turkey; |
| 78 | + } |
| 79 | + public void quack() { |
| 80 | + turkey.gobble(); |
| 81 | + } |
| 82 | + public void fly() { |
| 83 | + for (int i = 0; i < 5; i++) { |
| 84 | + turkey.fly(); |
| 85 | + } |
| 86 | + } |
| 87 | +} |
| 88 | +``` |
| 89 | + |
| 90 | +아래는 TurkeyAdapter를 사용하는 모습을 도식화한 그림이다. |
| 91 | + |
| 92 | + |
| 93 | + |
| 94 | +```java |
| 95 | +public class DuckTestDrive { |
| 96 | + public static void main(String[] args) { |
| 97 | + MallardDuck duck = new MallardDuck(); |
| 98 | + WildTurkey turkey = new WildTurkey(); |
| 99 | + Duck turkeyAdapter = new TurkeyAdapter(turkey); |
| 100 | + |
| 101 | + System.out.println("The Turkey says…"); |
| 102 | + turkey.gobble(); |
| 103 | + turkey.fly(); |
| 104 | + System.out.println("\nThe Duck says…"); |
| 105 | + testDuck(duck); |
| 106 | + System.out.println("\nThe TurkeyAdapter says…"); |
| 107 | + testDuck(turkeyAdapter); |
| 108 | + } |
| 109 | + static void testDuck(Duck duck) { |
| 110 | + duck.quack(); |
| 111 | + duck.fly(); |
| 112 | + }g |
| 113 | +} |
| 114 | +``` |
| 115 | + |
| 116 | +## 📌 [예시 2] 안드로이드에서 어댑터 패턴 (참고로만 보세요!) |
| 117 | + |
| 118 | +- 안드로이드에서의 어댑터는 뷰(Client)와 데이터 셋(Adaptee) 연결해주는 역할을 한다. |
| 119 | +- 어댑터는 데이터 아이템에 접근할 수 있도록 하며, 데이터 셋 속 아이템의 뷰를 그리는 역할도 담당한다. |
| 120 | + |
| 121 | + |
| 122 | + |
| 123 | +- 예를 들어 저런 리스트 목록 화면을 만든다고 가정하면 데이터를 올리는 부분에서 뷰와 데이터를 연결해주는 다리 역할을 하는 것이 어댑터이다. |
| 124 | +- data ← Adapter → AdapterView의 흐름으로 이루어져 있다. |
| 125 | +- 안드로이드 코드 예시 |
| 126 | + |
| 127 | +  |
| 128 | + |
| 129 | +  |
| 130 | + |
| 131 | + - 리스트 뷰에 들어가는 아이템들을 나타내는 xml파일인 rv_item.xml |
| 132 | + |
| 133 | + ```java |
| 134 | + <LinearLayout |
| 135 | + xmlns:android="http://schemas.android.com/apk/res/android" |
| 136 | + android:layout_width="match_parent" |
| 137 | + android:layout_height="match_parent"> |
| 138 | + |
| 139 | + <TextView |
| 140 | + android:text="rv" |
| 141 | + android:textSize="20sp" |
| 142 | + android:layout_margin="20dp" |
| 143 | + android:layout_width="wrap_content" |
| 144 | + android:layout_height="wrap_content"/> |
| 145 | + |
| 146 | + </LinearLayout> |
| 147 | + ``` |
| 148 | + |
| 149 | + - 데이터들이 모아져 있는 List가 있는 [MainActivity.](http://MainActivity.java)kt 파일 |
| 150 | + - 여기서는 데이터 관리 뿐만 아니라 리사이클러뷰(리스트뷰라고 생각하면 됩니다)와 어댑터를 연결한다. |
| 151 | + |
| 152 | + ```java |
| 153 | + class MainActivity : AppCompatActivity() { |
| 154 | + override fun onCreate(savedInstanceState: Bundle?) { |
| 155 | + super.onCreate(savedInstanceState) |
| 156 | + setContentView(R.layout.activity_main) |
| 157 | + |
| 158 | + val items=mutableListOf<String>() |
| 159 | + items.add("a") |
| 160 | + items.add("b") |
| 161 | + items.add("c") |
| 162 | + |
| 163 | + //activity_main에 있는 RecyclerView와 연결 |
| 164 | + val rv=findViewById<RecyclerView>(R.id.rv) |
| 165 | + val rvAdapter=RVAdapter(items) |
| 166 | + rv.adapter=rvAdapter |
| 167 | + |
| 168 | + rv.layoutManager=LinearLayoutManager(this) |
| 169 | + } |
| 170 | + } |
| 171 | + ``` |
| 172 | + |
| 173 | + - 아이템들이 들어있는 rv_item.xml과 MainActivity의 list안에 있는 데이터들을 연결해주는 RVAdapter.java |
| 174 | + |
| 175 | + ```java |
| 176 | + class RVAdapter(val items:MutableList<String>):RecyclerView.Adapter<RVAdapter.ViewHolder>(){ |
| 177 | + |
| 178 | + // 리사이클러뷰의 아이템 불러오기 |
| 179 | + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RVAdapter.ViewHolder { |
| 180 | + val view=LayoutInflater.from(parent.context).inflate(R.layout.rv_item,parent,false) |
| 181 | + // 뷰 홀더에 뷰 넣어주기 |
| 182 | + return ViewHolder(view) |
| 183 | + } |
| 184 | + |
| 185 | + override fun onBindViewHolder(holder: RVAdapter.ViewHolder, position: Int) { |
| 186 | + holder.bindItem(items[position]) |
| 187 | + } |
| 188 | + |
| 189 | + //전체 리사이클러뷰의 개수 |
| 190 | + override fun getItemCount(): Int { |
| 191 | + return items.size |
| 192 | + } |
| 193 | + |
| 194 | + //뷰 홀더 만들기 |
| 195 | + inner class ViewHolder(itemView: View) :RecyclerView.ViewHolder(itemView){ |
| 196 | + fun bindItem(item:String){ |
| 197 | + //item은 onBindViewHolder에서 넘겨준 items[postion]값 즉, 리스트 안의 원소들 (a,b,c) |
| 198 | + val rv_text=itemView.findViewById<TextView>(R.id.rvItem) |
| 199 | + rv_text.text=item |
| 200 | + } |
| 201 | + } |
| 202 | + |
| 203 | + } |
| 204 | + ``` |
| 205 | + |
| 206 | + |
| 207 | +## 참고 자료 |
| 208 | + |
| 209 | +[https://dev-cini.tistory.com/27](https://dev-cini.tistory.com/27) |
| 210 | + |
| 211 | +[https://wellsw.tistory.com/240](https://wellsw.tistory.com/240) |
| 212 | + |
| 213 | +[https://codingsmu.tistory.com/59](https://codingsmu.tistory.com/59) |
| 214 | + |
| 215 | +[https://velog.io/@haero_kim/우리는-이미-어댑터-패턴을-알고-있다](https://velog.io/@haero_kim/%EC%9A%B0%EB%A6%AC%EB%8A%94-%EC%9D%B4%EB%AF%B8-%EC%96%B4%EB%8C%91%ED%84%B0-%ED%8C%A8%ED%84%B4%EC%9D%84-%EC%95%8C%EA%B3%A0-%EC%9E%88%EB%8B%A4) |
| 216 | + |
| 217 | +헤드퍼스트 디자인 패턴 |
0 commit comments