2015년 9월 3일 목요일

클래스 디자인 패턴 7-1. Adapter Patter_

1. 개념잡기
    많이 쓰는 패턴, 비슷한 기능을 하거나 다른 기능을 하지만
      서로 다른 API로 제공되는 경우 이 중간에 어댑터 역할을
      하는 객체를 넣어 같은 기능을 하는걸로 보이게 함.
      현재 쓰고 있는 클래스(플러그, 타겟)
      , 이를 연결하려고 하는 클래스(클라이언트)
      , 이를 중간에 연결해주는 클래스(어댑터)
      로 구성되어 있음

     이 패턴을 이용해서 다른 메서드명을 가진 비슷한 메서드를
       같은 메서드인것처럼 사용할 수 있고
     실제 사용하는 곳에서는 메서드명칭이 다른 인스턴스에
       대해서 같은 명령으로 실행이 가능하는 장점이 생긴다.
   

2. 소스

1> Java Design P : 클래스 상속을 이용
  1) 사용해야할 메서드명을 가진 interface를 작성
 
public interface Print {
 public abstract void printWeak();
 public abstract void printStrong();
}


  2) 제공되고 있는 비슷한 기능을 하는 다른 이름의 메서드를
      보유하고 있는 클래스
 
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+"*");
 }
}


  3) 제공되는 클래스를 통일 시켜야할 메서드로 감싸기
 
public class PrintBanner extends Banner implements Print {
 public PrintBanner(String string) {
  super(string);
 }

 @Override
 public void printWeak() {
  showWithParen();
 }

 @Override
 public void printStrong() {
  showWithAster();
 }
}


  4) test코드를 주입할 mainTest  클래스

 
public class MainTest {
 public static void main(String[] args) {
  Print p = new PrintBanner("Hello");
  p.printWeak();
  p.printStrong();
 }
}


결과 : 
(Hello)
*Hello*


2> Java Design P : 인터페이스 위임을 이용
     1> 예제와 원칙적으로 같지만 Print 가 interface가 아닌 class
    이며(abstract class) 이렇게 되면 다중 상속이 안되는 자바
    에서는 Print를 상속받고 Banner는 멤버변수로 담아둔뒤
     생성자에서 PrintBanner 가 아닌 Banner를 넘기는 방식으로
     구현합니다.
  1) Print 수정
 
public abstract class Print {
 public abstract void printWeak();
 public abstract void printStrong();
}


  2) PrintBanner 수정
 
public class PrintBanner extends Print {
 private Banner banner ;
 
 public PrintBanner(String string) {
  //super(string);
  this.banner = new Banner(string);
 }

 @Override
 public void printWeak() {
  banner.showWithParen();
 }

 @Override
 public void printStrong() {
  banner.showWithAster();
 }
}


결과 :
(Hello)
*Hello*


3> 종합
  1) 먼저 전에 쓰고 있던 플러그, 타겟 를 작성
         (인터페이스 + 구현체)
 
package duckPlug;
public interface Iduck {
 public void quack();
 public void fly();
}

 
package duckPlug;
public class MallardDuck implements Iduck {

 @Override
 public void quack() {
  System.out.println("Quack");
 }

 @Override
 public void fly() {
  System.out.println("I'm flying");
 }
}


  2) 플러그에 연결할 다른 클래스 클라이언트 작성
         기능상 비슷한 기능이긴(울고, 날라가고) 한데 메서드
         명이 틀림
         (인터페이스 + 구현체)
 
package turkeyTarget;
public interface Iturkey {
 public void gobble();
 public void fly();
}

package turkeyTarget;
public class WildTurkey implements Iturkey {

 @Override
 public void gobble() {
  System.out.println("Gobble gobble");
 }

 @Override
 public void fly() {
  System.out.println("I', flying a short distance");
 }
}


  3) 이를 중간에서 연결할 어댑터를 작성
 
package adapterS;

import turkeyTarget.Iturkey;
import duckPlug.Iduck;

public class TurkeyAdapter implements Iduck {
 Iturkey turkey;
 
 public TurkeyAdapter(Iturkey turkey){
  this.turkey = turkey;
 }
 
 @Override
 public void quack() {
  turkey.gobble();
 }

 @Override
 public void fly() {
  for(int i=0; i< 5; i++){
   turkey.fly();
  }
 }
}


  4) 테스트 코드 작성
     Turkey 라는 클래스를 Duck 처럼 사용함, 이는 Iduck
       인터페이스를 상속하여 해당 메서드에서 Turkey 클래스의
       메서드와 대치하게끔 작성해서 가능해짐
     test코드에서 사용시에는 Adapter 만 접근하여
       Turkey를 Duck처럼 사용함.
 
package testP;

import adapterS.TurkeyAdapter;
import turkeyTarget.WildTurkey;
import duckPlug.Iduck;
import duckPlug.MallardDuck;

public class DuckTestDrive {
 public static void main(String[] args) {
  MallardDuck duck = new MallardDuck();
  WildTurkey turkey = new WildTurkey();
  Iduck turkeyAdapter = new TurkeyAdapter(turkey);
  
  System.out.println("1. the turkey says");
  turkey.gobble();
  turkey.fly();
  
  System.out.println("\n2. the Duck says");
//  duck.quack();
//  duck.fly();
  testDuck(duck);
  
  System.out.println("\n3. the TurkeyAdapter says");
//  turkeyAdapter.quack();
//  turkeyAdapter.fly();
  testDuck(turkeyAdapter);
 }

 static void testDuck(Iduck duck){
  duck.quack();
  duck.fly();
 }
}


결과 : 
1. the turkey says
Gobble gobble
I', flying a short distance

2. the Duck says
Quack
I'm flying

3. the TurkeyAdapter says
Gobble gobble
I', flying a short distance
I', flying a short distance
I', flying a short distance
I', flying a short distance
I', flying a short distance

3. 다이어그램
  하단 링크를 참고(자세한 설명은 덤)
     http://warmz.tistory.com/763


4. 관련있는 패턴
  1) Bridge 패턴
     Bridge는 기능과 구현을 연결하는 방식, Adapter는 다른 클래스의
     기능을 똑같이 사용하는 방법입니다.

  2) Decorator 패턴
     Adapter는 다른 클래스의 비슷한(같지않은) 기능을 같게 맞추는
       역할을 한다면 Decorator은 흐름 변경없이 기능을 추가하는
       패턴입니다.

댓글 없음:

댓글 쓰기