Adapter 패턴

gang_shik·2022년 3월 10일
0

Adapter 패턴

  • adapteradapt(개조) 시키는것, AC 어댑터의 역할은 직류 12볼트의 컴퓨터를 교류 100볼트의 환경에 맞게 바꾸는 것임

  • 이를 프로그래밍으로 생각을 한다면 이미 제공되어 있는 것을 그대로 사용할 수 없을 때, 필요한 형태교환하고 사용하는 일이 많은데 이미 제공되어 있는 것과 필요한 것 사이차이를 없애주는 디자인 패턴이 Adapter 패턴임

  • Adapter 패턴을 Wrapper 패턴이라고도 함 무엇인가를 한 번 포장해서 다른 용도로 사용할 수 있게 교환해주는 것이 wrapper이며 adapter임

  • 두 가지 종류가 존재함

    • 클래스에 의한 Adapter 패턴(상속을 사용한 Adapter 패턴)
    • 인스턴스에 의한 Adapter 패턴(위임을 사용한 Adapter 패턴)

예제1(상속을 사용한 Adapter 패턴)

  • 제공되고 있는 것 : Banner 클래스(showWithParen, showWithAster)
  • 교환장치(Adapter) : PrintBanner 클래스
  • 필요한 것 : Print 인터페이스(printWeak, printStrong)
public class Banner {
		private String string;
		public Banner(String string) {
				this.string = string;
		}
		public void showWithParen() {
				System.out.println("(" + string + ")");
		}
		public void showWithAster() {
				System.out.println("*" + string + "*");
		}
}
public interface Print {
		public abstract void printWeak();
		public abstract void printStrong();
}
public class PrintBanner extends Banner implements Print {
		public PrintBanner(String string) {
				super(string);
		}
		public void printWeak() {
				showWithParen();
		}
		public void printStrong() {
				showWithAster();
		}
}
  • Banner 클래스사용해서 Print 인터페이스충족시키는 클래스를 만드는 일을 함
  • PrintBanner 클래스어댑터 역할을 함 제공되어 있는 Banner 클래스상속해서 필요로 하는 Print 인터페이스구현
public class Main {
		public static void main(String[] args) {
				Print p = new PrintBanner("Hello");
				p.printWeak();
				p.printStrong();
		}
}
  • Main 클래스 내에서는 PrintBanner 인스턴스를 Print 인터페이스형의 변수로 대입함
  • Main 클래스는 Print라는 인터페이스를 사용해서 프로그래밍 함
  • Main 클래스를 전혀 바꾸지 않고 PrintBanner 클래스의 구현을 바꿀 수 있음(Banner 클래스나 showWithParen 메소드나 showWithAster 메소드는 Main 클래스의 소스 코드 상에서는 완전히 감추어짐)

예제2(위임을 사용한 Adapter 패턴)

  • 위임을 사용한다는 것은 어떤 메소드의 실제 처리다른 인스턴스의 메소드맡기는 것을 의미함
public class Banner {
		private String string;
		public Banner(String string) {
				this.string = string;
		}
		public void showWithParen() {
				System.out.println("(" + string + ")");
		}
		public void showWithAster() {
				System.out.println("*" + string + "*");
		}
}
public abstract class Print {
		public abstract void printWeak();
		public abstract void printStrong();
}
public class PrintBanner extends Print {
		private Banner banner;
		public PrintBanner(String string) {
				this.banner = new Banner(string);
		}
		public void printWeak() {
				banner.showWithParen();
		}
		public void printStrong() {
				banner.showWithAster();
		}
}
public class Main {
		public static void main(String[] args) {
				Print p = new PrintBanner("Hello");
				p.printWeak();
				p.printStrong();
		}
}
  • Print는 인터페이스가 아니고 추상클래스로 가정함
  • Banner 클래스를 사용해서 Print 클래스와 동일한 메소드를 갖는 클래스를 실현함
  • 2개의 클래스를 동시에 상속을 할 수 없기 때문에 PrintBanner 클래스는 banner 필드에서 Banner 클래스의 인스턴스를 가짐, 이 인스턴스는 PrintBanner 클래스의 생성자에서 생성함
  • printWeak 및 printStrong 메소드에서는 banner 필드매개로 showWithParen, showWithAster 메소드를 호출함, 이번에는 필드를 경유해서 호출함, 위임을 하는 것
  • PrintBanner 클래스에서 처리하는 게 아닌 Banner의 인스턴스인 showWithParen 메소드에 위임함

안드로이드?

  • 안드로이드에서도 ListView, RecyclerView를 활용할 경우, 여기서 Adapter가 등장을 함, 그리고 이 Adapter과 Adapter 패턴과의 연관성을 생각해 볼 수 있음

  • 예를 들어 아래와 같이 Tribble이라는 데이터를 리스트화해서 쭉 보여주기 위해서 RecyclerView를 사용한다고 할 때, RecyclerView의 경우 Adapter가 있는데 이를 적용하여서 데이터를 접목시킬 수 있음

  • 이렇게 되면 필요한 것은 Tribble이라는 List 데이터이고 제공되는 것은 RecyclerView라고 볼 수 있음, 이를 어떻게 RecyclerView에 리스트처럼 쭉 나타낼 것인가의 문제임

  • 그래서 대개 어댑터를 구현할 때 RecyclerView.Adapter를 상속받는데 이는 추상클래스로 제공되어서 TribbleAdapter라는 클래스가 교환장치 역할로 RecyclerView에서 리스트로 쭉 보여주는 것임

class TribbleAdapter(private val tribbles: List<Tribble>) : RecyclerView.Adapter<TribbleViewHolder>() {
  override fun onCreateViewHolder(viewGroup: ViewGroup, i: Int): TribbleViewHolder {
    val inflater = LayoutInflater.from(viewGroup.context)
    val view = inflater.inflate(R.layout.row_tribble, viewGroup, false)
    return TribbleViewHolder(view)
  }

  override fun onBindViewHolder(viewHolder: TribbleViewHolder, itemIndex: Int) {
    viewHolder.bind(tribbles[itemIndex])
  }

  override fun getItemCount() = tribbles.size
}
  • 이렇게 되면 이 RecyclerView가 구현되고 사용할 곳에서 TribbleAdapter를 생성하고 또 RecyclerView에서 List 형태로 쭉 나열될 데이터를 넣어주기만 하면 TribbleAdapter가 Adapter 패턴에서의 역할로써 data와 그리고 RecyclerView 사이를 접합시켜 RecyclerView에 원하는 데이터를 리스트형태로 보여줄 수 있게 처리되는 것으로 볼 수 있음

  • 하지만 여기서 한 번 더 생각할 것은 이게 실질적으로 체감상 자바 디자인 패턴에서 말하는 정도의 실제 안드로이드에서의 어댑터와는 살짝 다른 느낌이 있음 즉, 완벽하게 디자인 패턴에서의 어댑터다라고 말하기엔 안드로이드 스튜디오라는 프레임워크를 쓰는 것에 있어서 어댑터 패턴처럼 역할이 되어서 쓴 것이지 직접적인 연관성은 좀 다름

  • 오히려 자바 디자인 패턴에서의처럼의 처리는 안드로이드에선 MVC, MVP, MVVM 등의 구조적인 패턴으로 개선함을 생각해야함

  • 즉, 이런 디자인 패턴은 안드로이드 프레임워크를 사용함에 있어서 자연스럽게 적용되고 쓴다고 보면 좋음

    • Third Party 라이브러리 즉, Retrofit, Glide, 그리고 몇몇 컴포넌트들 경우 implements해서 라이브러리를 추가해서 쓰는데 이런 부분 자체가 외부 라이브러리를 안드로이드 프레임워크에서 자연스럽게 사용하기 때문에 이미 어댑터 패턴의 법칙이 내포되어 있다고 이해하면 됨
profile
측정할 수 없으면 관리할 수 없고, 관리할 수 없으면 개선시킬 수도 없다

0개의 댓글